perm filename LINED[S,SYS]84 blob sn#526436 filedate 1980-07-27 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00044 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00006 00002	BEGIN LINED
C00008 00003	GLOBAL LINE,KBDCHN,CHR
C00013 00004	KBDEDP PTLPUT PTLPU1 PTLPCC KBDED KBDBCA KBDX1 NOSTDM KBDX2 KBDKIL LSRSEE LSRSEX
C00020 00005	KBDBEG KBDBG1 NOINIT LE20 LE21 LE22 LE23
C00026 00006	LECCN LECCN2 NOHOLD
C00028 00007	LEC1 LECB LECBOK LECBNO NOTEOL EOLOK LECBL
C00032 00008	CLKRPT CLKSCN REPTPS DLYRPT LE2CR LE2B LEBSCK LE2 NOMCHK LE2X LE2XA LE2XB
C00040 00009	LE2A LE2NOS LEOVS LEOVD LEINS TXINS LEOVSC CKMETA CKBITS
C00047 00010	PUTLF PUTCHR PUTCH2 PUTCH3 PUTCH1
C00050 00011	INSTAB INST1 INST3 INST4 INST2 INSCHR INSCH1 LEINSW LEBGLP INSW1 LEPACK
C00056 00012	GCOLL GCOLL1 GCOLL3 PCHK GCOLL2 GCOLL4 GCOLL5
C00060 00013	LECT LECSP MVX1 MVX1A LECX LECX1 CKNFOR CKNFO2
C00064 00014	LECFF LEBS LEBS2 SRBAK2 BSP1 BSP2 BSP3 TXBSP DMMOVE MVX1C
C00070 00015	LECI ACTIVX INSP1 SRCHCR LECD LECDOV DMDELE DMDEL2 DMDEL3
C00074 00016	LECTX
C00076 00017	ADJNTB ADJTB LECD4A LECD6 LECD5 LECD5A
C00080 00018	SEARCH RESRCH SRCHL GETEM GETEM0 GETEM1 GETEM2
C00083 00019	SRBACK SRBAKL SRBKCR GETLFT GETLF3 GETLF0 GETLF1 GETLF2
C00087 00020	LEDESC ESCR ESCP ESCZ
C00089 00021	TTYESC
C00092 00022	CLEAR CLEARL LECRLF LECLR2 MCLEAR ESCCR1 ESCCR
C00096 00023	ESCC ESCC0 ESCC1 ESCC2 BRKP ESCG ESCL CKHOLD CTLBRK ESCLT ESCGT ESCGT2
C00100 00024	ESCJ ESCE ESCU ESCY ESCY1 ESCN ESCFF
C00102 00025	ESCH ESCO ESCDOX ESCF ESCDOT ESCDO4 ESCDO2 ESCDO3 ESCDO6 ESCDOC ESCDOM
C00109 00026	ESCV ESCW ESCW0 ESCW3 ESCW2 ESCW1 NXTWHO ESCQ ESCQY ESCQX
C00116 00027	ESCI ESCX ESCX2 ESCX1 ESC2X ESC2X1 REWHO ESC2X2 ESC2X3 ESC2X5
C00121 00028	FNTAB FNT1 FNT4 FNT3 FNT2 FNT5
C00123 00029	MOVEIT MVFOR MVBAK MVA MVA1 MVA2
C00127 00030	INIT2 INIT4 INIT4B INIT4A INIT4C CRKILL
C00130 00031	INITIT INIT3 INIT1 LEINIT
C00133 00032	LACTV1 LACTIV PTLLX ACTNON ACTIV1 ACTNH0
C00138 00033	ACTIV3 ACTIV9 ACTIVL ACTIV6 ACTIVQ ACTIVP ACTIVR ACTIVS ACTIVZ ACTIVY ACTIV4 ACTIV5
C00146 00034	ACTIV2 ACTI21 ACTIV7 ACTIV8 ACTI10
C00148 00035	ECHOCB ECHO SHIFT SHIFTR SHIFTL SHIFT2
C00150 00036	PTLOAD PTL7W9 PTLLED EPTL1 EPTL2 PTLL0 PTLL4 PTLL3 PTLL09 PTLL2 PTLLX1 PTLLX9 RSTECH PTLLX0
C00156 00037	QLETX2 QLETXF QLETXT QLECUR LEFLUS
C00158 00038	MAKECR LEFIX MAKEC1
C00160 00039	MAKE12 MAKE23 MAKE22 MAKE20 MAKE21 MAKE24 MAKEC8 MAKEC9 MAKEC7 MAKE10
C00163 00040	MAKEC2 MAKEC6 MAKE17 MAKE18
C00166 00041	MAKEC3 MAKEC4 MAKE16
C00169 00042	MAKE15 MAKE13 MAKE14 MAKEC5
C00171 00043	MAKE11 MAKINS
C00172 00044	QU2DMC QUODMX QUODMC QU2DM3 QU2DM2 PUTDMC PUTDM2 GETLEQ
C00177 ENDMK
C⊗;
BEGIN LINED

COMMENT ⊗  THIS IS THE INCREDIBLE INTRA-LINE EDITOR. ITS FEATURES ARE:

	CTRL SPACE-- MOVE FORWARD THROUGH LINE.
	CTRL BS-- MOVE BACKWARD.
	BS -- MOVE BACKWARD, DELETING (END OF LINE ONLY).
	META BS -- MOVE BACKWARD, DELETING.
	CTRL I	-- ENTER INSERT MODE (MIDDLE OF LINE ONLY).
	CTRL D -- DELETE FORWARD (MIDDLE OF LINE ONLY).
	CTRL TAB -- MOVE TO END OF LINE.
	CTRL FORM -- MOVE TO BEGINNING OF LINE.
	CLEAR -- DELETE ENTIRE LINE.
	CTRL S<ANY CHR.> -- MOVE POINTER RIGHT TO NEXT OCCURRENCE OF <ANY CHR.>.
		IF <ANY CHR> IS CR, MOVES TO END OF LINE
	CTRL K<ANY CHR.> -- DELETE RIGHT TO NEXT OCCURRENCE OF <ANY CHR.>.
		IF <ANY CHR> IS CR, KILLS TO END OF LINE
	CTRL R -- REPEAT LAST CTRL S OR CTRL K COMMAND GIVEN, USING SAME CHAR.

	CTRL CR -- (ONLY AT START OF LINE OR AFTER CLEAR) RETRIEVES THE
		LAST LINE TYPED IN.

	META<ANY CHR.> -- INSERT <ANY CHR.> IN FRONT OF CURSOR (MIDDLE OF LINE ONLY)

ANY COMMAND MAY BE PRECEDED BY A REPEAT NUMBER (TYPED WITH CTRL KEY).
    FOR EXAMPLE, CTRL 9 CTRL BS MOVES THE POINTER BACK 9 CHARACTERS.
ANY CTRL COMMAND LEAVES INSERT MODE, AS DOES ANY META<CHAR>, EXCEPT META<BS>.

WHAT COULD BE MORE WONDERFUL ??
⊗

GLOBAL LINE,KBDCHN,CHR

;J←ITEM ;USED TO BE I←ITEM

CBIT1←←1	;CTRL BIT 1 (CONTROL)
CBIT2←←2	;CTRL BIT 2 (META)
EOLCHR←←12	;LINE FEED TERMINATES THE LINE IN THE BUFFER.

	;;STATUS BITS (LEFT HALF OF J).

↑WTFLAG←←1	;WAITING FOR PRGM. TO SWALLOW LAST LINE.
EOLBT←←2	;AT END OF LINE.
INSBT←←4	;INSERT MODE (MIDDLE OF LINE).
TABB←←10	;LOCATION OF NEXT TAB IN NTABPT, SIZE IN NTABCT.
NOTABB←←20	;NO TAB BETWEEN CURRENT POS. AND END OF LINE.
DMDAMN←←40	;Extra hard case--absolutely must redraw whole LE for now
	;DMDAMN is set: if LE has ≤ 1 char in it, or if CLEAR or ESC R typed, or
	;		if we have to delete anything when line wraps around
XTABBT←←100	;WE ARE INSIDE A TAB IN GETEM OR MOVEIT
	;XTABBT is also used to distinguish forward searches from reverse searches
;;;SHLDRB←←200	;Loser wants to see every chr. we see.
DMHARD←←200	;Insertions or deletions required--redraw all if line wraps around.
SRCHBT←←400	;CONTROL-S SEEN, NEXT CHR. IS SEARCH ARGUMENT.
KILLBT←←1000	;CONTROL-K SEEN....
REEDBT←←2000	;WE ARE RE-EDITING A LINE (AFTER A CONTROL-CR).
↑↑NOCRBT←←4000	;WE SHOULD NOT PUT ANOTHER CR INTO THIS LINE.
	;NOCRBT is also used to distinguish CLEARed line from ACTIV1ated line
NOTEXT←←10000	; THIS BIT MEANS THE TEXT HAS NOT BEEN CHANGED, JUST THE CURSOR
NOTFR←←20000	; MEANS THAT NO TRANSFER AT ALL SHOULD TAKE PLACE
CRBIT←←40000	; USED TO SKIP OVER CRLF IN MIDDLE OF LINE IN GETEM
	;CRBIT is also used as flag to LECD, ADJTB, and INSTAB to suppress DM output
NOBRBT←←100000	; MEANS LINE HAS NOT BEEN BROKEN UP. LONG LINES ONLY.
ACTNOW←←200000	; MEANS WE SHOULD ACTIVATE NOW
;400000 (SIGN BIT) MEANS LINE EDITOR HAS BEEN INITIALIZED (I.E., SOME
;		   TEXT HAS BEEN TYPED INTO LINE EDITOR SINCE LAST ACTIVATION)

IFE FTF2,<	;NOTE: DPYSER USES A different NO-OP!
DISNOP←←12	;ACTUALLY TSS, BUT A GOOD NOP WITH ALL BITS OFF.
>;IFE FTF2

↑↑XDEL:	14B10	;X-SIZE OF A SIZE 2 CHARACTER, POSTIONED AT THE X-FIELD.
XDEL2:	14B11	;ONE HALF OF ABOVE.
;KBDEDP PTLPUT PTLPU1 PTLPCC KBDED KBDBCA KBDX1 NOSTDM KBDX2 KBDKIL LSRSEE LSRSEX

COMMENT ⊗ KBDED IS CALLED AT UUO OR INTERRUPT LEVELS FROM RECINT,
          WITH CHR CONTAINING THE CHAR TO BE CONSIDERED WITH ITS
          CTRL BITS IN PLACE.
        UCHN CONTAINS JUST THE CTRL BITS, RIGHT JUSTIFIED.
        DSER CONTAINS THE LOWER-CASE VERSION OF THE CHARACTER IN CHR.
        DDB AND LINE ARE SETUP TO THE RIGHT TTY, AS IS IOS.
        PROG, IOS, AND UUO ARE PRESERVED BY KBDED. 
⊗

↑↑KBDEDP:
	TLNN IOS,PTLIP		;IF NOT PTLOAD IN PROGRESS,
	JRST KBDED		;  THEN DO THE LINE EDITOR BIT
	TLNE LINE,FCS		;NOT FULL CHAR. SET MODE?
	JRST PTLPUT		;No case conversion
	LDB TAC,[POINT 7,CHR,35] ;Get char without bucky bits
	CAIL TAC,"A"		;Yes, is it a letter?
	CAILE TAC,"z"
	JRST PTLPUT		;Definitely not.
	CAILE TAC,"Z"		;Skip if upper case letter
	CAIL TAC,"a"		;Don't skip if lower case letter
	TRC CHR,40		;Complement case (upper to lower or vice versa).
PTLPUT:	TRNE CHR,10000
	POPJ P,			;DON'T TRY TO STORE ESCAPE COMMANDS
	TRNN CHR,177
	JRST PTLPCC		;USER TYPING CALL DURING PTLOAD
	MOVE TAC,PTLPTR		;GET BPT TO STORE INTO
	CAME TAC,[POINT 9,PTLBUF+PTLBUL-1,26]
PTLPU1:	IDPB CHR,PTLPTR		;OK, DEPOSIT CHAR
	POPJ P,

PTLPCC:	SETZM PTLBUF		;HE TYPED CALL, FLUSH ANY OTHER TYPEAHEAD
	MOVE TAC,[PTLBUF,,PTLBUF+1]
	BLT TAC,PTLBUF+PTLBUL-1
	MOVE TAC,[POINT 9,PTLBUF]
	MOVEM TAC,PTLPTR
	MOVEM TAC,PTLTKR	;IN CASE HE'S READING THE BUFFER BUFFER ALREADY
	JRST PTLPU1

↑KBDED:	MOVE DAT,LINE		;GET DPY NO. AND LINTAB BITS INTO DAT.
	MOVE J,LETAB(DAT)	;LOAD J WITH PTR TO CONTROL BLOCK AND BITS
	TLZ J,NOTEXT!NOTFR!CRBIT!DMHARD!DMDAMN
	SETOM LEINV(J)		; SET BUFFER INVALID
	SETOM LEACT(J)		; MAKE SURE WE STICK AROUND FOR ANOTHER MINUTE
;;;	TLNE J,SHLDRB		;Loser looking over our shoulder ?
;;;	PUSHJ P,LSRSEE		;Hold up chr. for him to see. Hope he likes it.
KBDBCA:	PUSHJ P,KBDBEG		; DO LINE EDITOR BIT
	SETZM LEINV(J)
	MOVE AC1,FCPOS(J)	;Number of chars in line
	TLNN J,WTFLAG		;If we are busy activating now,
	SOJG AC1,.+2		;  or if less than two chars in line,
	TLO J,DMDAMN		;  then force redrawing whole DM line editor
	TLZE J,NOTFR		; WAS THIS A SILENT COMMAND?
	JRST KBDX1		; YES, JUST LEAVE QUIETLY
	TLNE J,NOTEXT		; HAS THE TEXT BEEN CHANGED?
	PUSHJ P,QLECUR		; NO, JUST UPDATE THE CURSOR
	TLZE J,NOTEXT
KBDX1:	SKIPE LEWAKE(J)		; DID WE CAUSE A TRANSFER TO ABORT?
	PUSHJ P,QLETX2		; YES, UPDATE BOTH
	SETZM LEWAKE(J)		; CLEAR ABORT FLAG
	MOVE AC1,PRGNUM(J)	; PICK UP TTY NUMBER
	HLLM J,LETAB(AC1)	; STORE FINAL BITS
	SKIPN LETXC(J)		;Don't start incremental output if need redraw all
	TLNE IOS,PTLIP		;Don't start output while doing PTLOAD
	JRST NOSTDM
	MOVE DAT,J		;Dpy header in DAT for STRTDM
	PUSH P,IOS
	TLNE AC1,DMLIN
	PUSHJ P,STRTDM		;Make sure incremental LE gets output
	POP P,IOS
	MOVE J,DAT
NOSTDM:	TLNE J,WTFLAG		;ARE WE CURRENTLY ACTIVATING SOMETHING?
	POPJ P,			;YES, SNEAK WILL GET WOKEN UP LATER!
	JUMPGE J,KBDKIL		;Jump if line editor not initialized (nothing there)
	TLNE IOS,SNKWAT		; IN SNEAK WAIT?
	SKIPG FCPOS(J)		; ANYTHING FOR HIM TO SEE?
	JRST KBDKIL		;We should kill this guy's tty if not logged in
KBDX2:	TLNE IOS,TPMON
	POPJ P,			;Don't wake up job if TTY is in monitor mode
	MOVE IOS,[XWD TTYIOW!SNKWAT,IOACT]	;YES, CLEAR FLAGS
	ANDCAB IOS,DEVIOS(DDB)
	JRST STTIOD		;BRING HIM OUT OF WAIT

↑KBDKIL:LDB J,PJOBN		;Any job using this tty?
	JUMPN J,CPOPJ		;Yes
	LDB TAC1,PUNIT		;No, get line number
	MOVE TAC,TTYTAB(TAC1)
	TLNE TAC,COMBIT!DLYBIT!PAUSEB	;Any command going on here?
	POPJ P,			;Yes
	JRST TTYKIL		;No, kill tty now

REPEAT 0,<	;POOLE MODE FLUSHED!!!
LSRSEE:	PUSH P,DAT
	MOVEI DAT,TTIBUF(DDB)
	PUSHJ P,PUTCHI		;Put chr. in loser's input buffer.
	 JFCL			;Buffer full. Loser loses.
	MOVE AC1,TIFCTR(DDB)
	CAIG AC1,TTICHR/4	;Is his buffer getting full ?
	TLNN IOS,TTYIOW		;Is he waiting for input ?
	JRST LSRSEX		;No.
	PUSHJ P,SYNCHA		;Prepare to activate loser.
	PUSHJ P,KBDX2		;Wake him up.
LSRSEX:	POP P,DAT
	POPJ P,
>
;KBDBEG KBDBG1 NOINIT LE20 LE21 LE22 LE23

KBDBEG:	SKIPE III(J)
	JRST KBDBG1
	MOVE AC3,CURPP(J)
	MOVE AC2,DPHPOS(AC3)
	SKIPGE LEPOS(J)
	TDZA AC2,AC2
	ADD AC2,LNLNGT(AC3)
	MOVEM AC2,PPHPOS(J)
KBDBG1:	TRNE CHR,10000
	JRST LEDESC		;<ESC>SOMETHING
	TRNN CHR,177		;IS THIS MAYBE A CALL?
	JRST LECCN		;A CALL WILL BE A NULL NOW.
	JUMPL J,NOINIT		;IS THIS THE FIRST CHAR OF A LINE?
	TLNE J,WTFLAG		;YES, IS LAST LINE IN USER BUFFER YET?
	JRST TPOPJ		;NO, JUST IGNORE HIM
	PUSHJ P,INIT2		;CLEANSE THE WORLD
NOINIT:	ANDI CHR,177		;REMOVE CTRL BITS FROM CHR.
	TLNN IOS,PTLIP		;Don't complement case during PTLOAD
	TLNE DAT,FCS		;NOT FULL CHAR. SET MODE?
	JRST LE20		;No case conversion
	CAIL CHR,"A"		;Yes, is it a letter?
	CAILE CHR,"z"
	JRST LE20		;Definitely not.
	CAILE CHR,"Z"		;Skip if upper case letter
	CAIL CHR,"a"		;Don't skip if lower case letter
	TRC CHR,40		;Complement case (upper to lower or vice versa).
LE20:	TLZE J,SRCHBT		;WAS LAST CHR. AN S OR K COMMAND ?
	JRST SEARCH		;YES.
	TLNE IOS,TPMON		;IGNORE ALLACT AND BSACT IN MONITOR MODE
	JRST LE23
	MOVEI AC2,ALLACT	;SETACT BIT TO ACTIVATE ON ALL BUCKY BITS AND BS
	TDNE AC2,ACTMOD(DDB)
	TLNE J,REEDBT		;IGNORE ALLACT IF RE-EDITING A LINE
	JRST LE21		;NO SPECIAL TREATMENT
	JUMPG UCHN,LE2		;GIVE HIM CHAR WITH SOME BUCKY BITS
	JRST LE22

LE21:	MOVEI AC2,BSACT
	SKIPN FCPOS(J)		;IGNORE BSACT UNLESS EMPTY LINE
	TDNN AC2,ACTMOD(DDB)
	JRST LE23
LE22:	CAIN CHR,177
	JRST LE2		;GIVE HIM THE BS
LE23:	CAIE CHR,177		;IF IT'S A BACKSPACE, PRETEND IT HAS CONTROL BIT.
	CAIN UCHN,CBIT1		;DO WE HAVE CONTROL BIT ONLY?
	TLNE IOS,DDTM		;YES. IS EDITOR DISABLED?
	JRST LE2B		;NOT A COMMAND, UNLESS CTRL-META-SPACE.
	CAIG CHR,"9"		;CONTROL BIT ONLY IS ON.  IS IT A DIGIT?
	CAIGE CHR,"0"
	JRST LEC1		;NO. CONTROL-LETTER, OR RUBOUT
	MOVE AC1,NUMARG(J)	;YES. CTRL NUMBERS ARE PART OF REPEAT ARGUMENT.
	IMULI AC1,=10		;DO DECIMAL CONVERSION.
	ADDI AC1,-"0"(CHR)
	ANDI AC1,777		;DON'T LET IT GET TOO BIG.
	MOVEM AC1,NUMARG(J)
	POPJ P,
;LECCN LECCN2 NOHOLD

LECCN:	PUSH P,J		;SAVE THE DPY PROGRAM HEADER ADDRESS
	PUSHJ P,RECINB
	POP P,J
	HRRZ DAT,LINE		;RECINB CLOBBERS THIS
	JUMPGE J,LECCN2		;DON'T NEED CRLF IF LINE EDITOR NOT INITIALIZED
	SKIPE LEPNT1(J)		;BH 12/10/77 THIS WON'T WORK IF NO LINE EDITOR YET
	PUSHJ P,LECRLF		;PUT CRLF ON END OF LINE EDITOR BEFORE FLUSHING
LECCN2:	PUSHJ P,NOHOLD		;MAKE SURE WE ARE NOT HOLDING
	PUSH P,DDB		;SAVE AN AC
	MOVEI DDB,LEB(J)	;TURN OFF EDITOR BUFFER BY
	HRLI DDB,DISJMP		;PUTTING A RETURN JUMP
	MOVSM DDB,LEPPV(J)	;ON TOP OF THE POSITION VECTOR.
	POP P,DDB
	HRRZS J,LETAB(DAT)	;RESET STATUS
	POPJ P,

;HERE TO MAKE SURE WE ARE NOT HOLDING.  PLANTS CLOCK REQ TO UNHOLD IF NECESSARY.
NOHOLD:	SETZ AC1,
	EXCH AC1,DPHOLD(J)
	JUMPE AC1,CPOPJ		;IF NOT HOLDING, DON'T UNHOLD!
	HRRZ AC1,PRGNUM(J)	;TTY NUMBER FOR UNHOLD
	HRLI AC1,UNHOLD		;ROUTINE TO CALL AT CLOCK LEVEL
	JRST AC1CLK		;PLANT CLOCK REQUEST THAT IS IN AC1
;LEC1 LECB LECBOK LECBNO NOTEOL EOLOK LECBL

LEC1:	JUMPE UCHN,LECB		;HERE FOR CONTROL-LETTER OR RUBOUT
	CAIN CHR,177
	CAIE UCHN,CBIT2		;META-BS DOESN'T CLEAR INSERT MODE!!
	SKIPA AC1,XDEL		;GET X DIMENSION OF A CHR.
	JRST LECB
	TLZE J,INSBT		;LEAVE INSERT MODE, IF WE ARE IN IT.
	PUSHJ P,INSP1		;READJUST CURSOR POSITION.
LECB:	SKIPN AC1,NUMARG(J)	;DID GUY TYPE RPT ARG ?
	AOS AC1,NUMARG(J)	;NO. USE 1.
	CAIN CHR,177
	JRST LEBS		;BACKSPACE.
	CAIN CHR," "
	JRST LECSP		;CONTROL-SPACE.
	CAIN CHR,14
	JRST LECFF		;CONTROL-FF
	TRZ DSER,40		;CHANGE LOWER CASE LETTERS TO UPPER.
	HLRZ AC2,TTYTAB(DAT)	;Pick up COMBIT and DLYBIT
	TRNN AC2,COMBIT!DLYBIT	;If either is on, assume user mode
	MOVE AC2,IOS		;Pick up TPMON
	HRR AC2,ACTMOD(DDB)	;Get special mode bits from activation table
	TDNE AC2,[TPMON,,SUPEOL];In monitor mode or SUPEOL mode,
	JRST LECBOK		; let line editor commands be line editor cmds
	TRNE AC2,SUPCT		;Want to suppress new line editor features?
	JRST LECBNO		;Yes, don't allow backward movement cmds
	SKIPN FCPOS(J)		;Anything in line editor?
	JRST LE2		;No, can't be a line editor command
LECBOK:	CAIN DSER,"T"		;Want to transpose two chars?
	JRST LECTX		;Yes
	CAIN DSER,"R"		;Want to repeat a search/kill
	JRST RESRCH		;Yes
	CAIN DSER,"L"		;Want to kill backwards?
	TLOA J,KILLBT		;Yes
	CAIN DSER,"B"		;Want to search backwards?
	JRST LECBL		;Yes
LECBNO:	TLNN AC2,TPMON		;Monitor treats all line editor cmds as such
	TLNN J,EOLBT		;But user at end of line doesn't get some
	JRST NOTEOL		;Let line editor cmds be such
	TRNE AC2,SUPEOL		;Want most LE cmds not to activate at eol?
	JRST EOLOK		;Yes
	JRST LE2		;No, not a line editor command now

;SUPEOL DOESN'T SUPPRESS ACTIVATION BY CONTROL-D OR CONTROL-I AT EOL
NOTEOL:	CAIN DSER,"D"		;COMPARE UNSHIFTED CHAR.
	JRST LECD		;CONTROL-D
	CAIN DSER,"I"
	JRST LECI		;CONTROL-I
EOLOK:	CAIN CHR,11
	JRST LECT		;CONTROL-TAB
	CAIN DSER,"R"
	JRST RESRCH		;CONTROL-R - REPEAT PREVIOUS CTRL-S OR CTRL-K
	CAIN DSER,"K"
	TLOA J,KILLBT		;CONTROL-K
	CAIN DSER,"S"
	TLOA J,SRCHBT		;CONTROL-S
	JRST LE2		;RANDOM CTRL LETTER.
	SETZM LESVCH(J)		;FLAG THIS AS A FORWARD SEARCH
	JRST LECX1		;STORE NEW BITS IN J AND EXIT.

LECBL:	MOVSI AC2,XTABBT	;FLAG THIS AS A BACKWARDS SEARCH
	HLLZM AC2,LESVCH(J)
	TLO J,SRCHBT
	JRST LECX1		;STORE NEW BITS IN J AND EXIT
;CLKRPT CLKSCN REPTPS DLYRPT LE2CR LE2B LEBSCK LE2 NOMCHK LE2X LE2XA LE2XB

IFN FTREPT,<
;Here at CLK level for request to repeat line editor command
↑↑CLKRPT:MOVEI LINE,DPYL0(TAC)	;GET LOGICAL TTY LINE NUMBER
	SKIPN LETAB(LINE)	;GET LOGICAL DPY HDR
	POPJ P,			;CAN'T REPEAT WITHOUT DPY HDR
	OFFSCN
	LDB AC2,[DDQREQ+LINE,,LSTESC] ;GET TTY RESPONSIBILITY FIELD
	CAIL AC2,TTPLEN		;LEGAL LINE NUMBER?
	JRST SCNONJ		;NOPE
	HLL AC2,LINTAB(AC2)	;GET LINE CHARACTERISTICS
	LDB AC1,[POINT PUNITS,LINTAB(AC2),35] ;GET LINE PHYSICAL TTY IS MAPPED TO
	CAIN AC1,(LINE)		;FORGET IT IF HE'S NOT STILL MAPPED TO US
	TLNN AC2,DDDLIN!DISLIN	;CAN ONLY TTREAD THE DD AND III KBDS
	JRST SCNONJ
IFN FTSPWT,<
	HRRE TAC,LINBIT(AC2)	;SEE IF THIS KBD IS ON THE DCA SCANNER
	JUMPGE TAC,CLKSCN	;JUMP IF ON THE KBD SCANNER
	MOVSI AC1,LEDSPW	;TELL DCASER THAT WE'RE REPEAT LINE EDITOR CMD
	IORB AC1,KBDCHR(AC2)	;SET REPEAT FLAG, SEE IF SPW REQ ALREADY MADE
	JUMPL AC1,SCNONJ	;JUMP IF SPW REQ IN PROGRESS ALREADY
	MOVEI LINE,(AC2)	;GET LINE NUMBER TO READ
	PUSHJ P,REQSPW		;PLANT SPW REQ FOR THAT LINE
	JRST SCNONJ		;AND WAIT FOR SPW CHAR TO COME BACK

>;FTSPWT
CLKSCN:	MOVEI TAC,-DPYL0(AC2)	;NORMALIZE LINE NUMBER FOR TTREAD
	PUSHJ P,TTRED0		;DO A TTREAD TO PEEK AT KBD
	 SKIPN TTYTAB(LINE)	;PEEKED OK, MAKE SURE THERE IS A LOGICAL DDB
	JRST SCNONJ		;NO DDB OR ILLEGAL LINE NUMBER, DON'T REPEAT
	HLRZ AC2,AC1		;KBD LINE WE PEEKED
	MOVEM AC1,DKBCHR	;SIMULATE KBDINT
	ANDI AC1,31477		;IGNORE TOP AND SHIFT
	CAIE AC1,30074		;CONTROL-META BS?
	CAIN AC1,30040		;OR CONTROL-META SPACE?
	CAIE AC2,(TAC)		;YES, BUT DID WE GET DATA FOR RIGHT KBD?
	JRST SCNONJ		;NO, DON'T REPEAT
	PUSHJ P,DKBCLK		;SEND THE REPEATED CHAR DOWN THE TUBES
	JRST SCNONJ
	
REPTPS←←=10	;NUMBER OF REPEATS PER SECOND
DLYRPT:	TLNN DAT,DDDLIN!DISLIN	;ONLY REPEAT IF MICROSWITCH KBD
	POPJ P,
	MOVEI AC2,-DPYL0(DAT)	;LINE NUMBER RELATIVE TO KBD SCANNER
	LSH AC2,=12
	ADDI AC2,JIFSEC/REPTPS	;DELAY TIME TILL NEXT REPEAT
	TLO AC2,$CLKRPT		;CLOCK ROUTINE TO CALL LATER
	CLKENQ(AC2)		;Plant clk req
	POPJ P,
>;FTREPT

LE2CR:	PUSHJ P,LECT		;SIMULATE A CTRL TAB (GO TO END OF LINE).
	MOVEI CHR,15		; RESTORE THE CR THAT MAKECR CLOBBERS
LE2B:	CAIN UCHN,CBIT1!CBIT2
	CAIE CHR," "		;IS THIS CTRL-META-SPACE?
	JRST LE2		;NOPE, JUST PUT IT INTO BUFFER
IFN FTREPT,<
	PUSHJ P,DLYRPT		;YES, PLANT CLOCK REQ FOR REPEATING LATER
>;IFN FTREPT
	MOVEI UCHN,CBIT1	;GIVE US A CTRL-SPACE
	JRST LEC1		;GO PROCESS ONE CTRL-SPACE NOW

LEBSCK:
IFN FTREPT,<
	PUSHJ P,DLYRPT		;PLANT CLOCK REQ FOR REPEATING LATER
>;IFN FTREPT
	MOVEI UCHN,CBIT1	;TURN CONTROL-META-BS INTO CONTROL-BS
	JRST LEBS2		;NOW PROCESS ONE CONTROL-BS

;;Here if CHR is not line editor command, so we put it into the LE buffer
LE2:	TLNN J,EOLBT		;AT END OF LINE ?
	JRST LE2A		;NO.
	PUSHJ P,CKBITS		;See if this char is allowed to have bucky bits
	TLNE J,NOCRBT		;ARE WE RE-EDITING THIS LINE ?
	CAIE CHR,15		;YES. DON'T PUT ANOTHER CR AT ITS END.
	SKIPA
	JRST ACTIV1		;JUST ACTIVATE GUY WHEN HE TYPES CR AT A RE-EDITED LINE.
	TLO J,CRBIT		;This case is always easy, even if char is a tab
	MOVE AC2,ACTMOD(DDB)
	TRNN AC2,SUPEOL		;WANT TO SUPPRESS META AT EOL?
	JRST NOMCHK		;NO
	TRNE AC2,ALLACT		;IF HE WANTS ALL ACTIVATORS,
	TLNE J,REEDBT		; AND IS NOT REEDITING, THEN GIVE HIM HIS METAS
	PUSHJ P,CKMETA		;SEE IF WE CAN FLUSH META BIT
NOMCHK:	PUSHJ P,PUTCHR		;PLACE CHAR. IN BUFFER.
	TLZ J,CRBIT
	MOVEM TAC,FCPOS(J)	;UPDATE FINAL CHAR. POS. CTR.
	JUMPG UCHN,ACTIV1	;ACTIVATE ON ANY CTRL BITS AT EOL.
	TLNN DAT,DMLIN
	JRST LE2X
	PUSH P,CHR
	MOVEI CHR,EEOL		;Put out quoted erase-to-eol char
	PUSHJ P,QUODMX		; in case just wrapped around
	POP P,CHR
LE2X:	MOVE TAC,SPCTAB(CHR)	;SPECIAL BITS.
	TLNN TAC,BREAKB!FCSBRK	;A BREAK CHAR. ?
	TLNE IOS,DDTM		;IS EVERY CHAR. AN ACTIVATOR ?
	JRST ACTIV1		;YES.
	TLNE J,ACTNOW		; ARE WE OUT OF BUFFER SPACE?
	JRST ACTIV1		; YES, ACTIVATE NOW
	TLNE DAT,SPCBRK		;ARE WE IN SPECIAL ACTIVATION MODE?
	TLNE IOS,TPMON
	JRST LE2XA		;NO
	PUSHJ P,SPCACT		;TEST FOR BREAK.
	 CAIA
LE2XA:	TRNE UCHN,CBIT1		;YES. ANY CTRL BITS ?
	JRST ACTIV1		;YES.
	CAIN CHR,11
	JRST LECX		;We have already inserted spaces for this tab
	TLNE DAT,DMLIN
	TLNE J,DMDAMN		;Need to redraw whole editor?
	JRST LECX		;Not DM or redrawing whole thing
	TLNE J,DMHARD
	JRST LE2XB		;Must insert char
	PUSHJ P,PUTDMC		;Easy--just put out character
	JRST LECX		;Done

LE2XB:	PUSH P,CHR
	MOVEI CHR,ID		;ID mode on
	PUSHJ P,QUODMX
	MOVEI CHR,IDADDC	;Add a space
	PUSHJ P,QUODMX
	MOVEI CHR,CANCEL	;ID mode off
	PUSHJ P,QUODMX
	POP P,CHR
	PUSHJ P,PUTDMC		;Type character over space
	JRST LECX
;LE2A LE2NOS LEOVS LEOVD LEINS TXINS LEOVSC CKMETA CKBITS

;Here with character typed not at end of line
LE2A:	TRNN UCHN,CBIT2		;INSERT CHAR. IF META OR CTRL-I (OR BOTH)
	TLNE J,INSBT		;ARE WE IN INSERT MODE ?
	JRST LEINS		;YES.
	CAIN CHR,15
	JRST LE2CR		;CR'S GO AT END OF LINE.
	TRNE UCHN,CBIT1		;NOW IF CONTROL BIT IS ON
	JRST LEINS		; THEN INSERT CHAR
	MOVE AC1,SPCTAB(CHR)	;GET BITS FOR THIS CHAR
	TLNE AC1,BREAKB!FCSBRK	;IS IT A BREAK CHAR?
	JRST LEINS		;YES, INSERT (LF OR ALT OR RUBOUT)
	TLNN DAT,SPCBRK		;NO, ARE WE IN SPECIAL ACTIVATION MODE?
	JRST LE2NOS
	PUSHJ P,SPCACT		;IS THIS CHAR A SPECIAL ACTIVATOR?
	 JRST LEINS		;YES, INSERT IT
LE2NOS:	PUSH P,CHR		;WE'RE OVER-STRIKING. SAVE CHAR.
	MOVEI AC1,1		;FAKE A RPT. ARG. OF 1.
	MOVE TAC,LEPNT1(J)	;IF WE ARE ABOUT TO OVERSTRIKE
	CAIE CHR,11		;Overtyping is trivial unless typing tab over non-tab
	TLO J,CRBIT		;Flag LECD and ADJTB to not put out DM chars
LEOVS:	ILDB AC2,TAC		;A TAB, AND IF THE TAB IS MORE
	JUMPE AC2,.-1
	CAIE AC2,11		; IS THIS A TAB?
	JRST LEOVD		; NO, JUST GO AHEAD AND OVERSTRIKE.
	ILDB AC3,TAC		;WE WILL INSERT INSTEAD.
	JUMPE AC3,.-1		; NO NULLS, PLEASE.
	CAIE AC3," "		; IS THIS REALLY A TAB OR A LONG LINE CRLF?
	JRST LEOVSC		; IS LONG LINE CRLF, READ PAST IT
	ILDB AC3,TAC		; PICK UP CHARACTER PAST SPACE
	JUMPE AC3,.-1
	CAIN CHR,11		;ALWAYS OVERTYPE IF NEW CHAR IS TAB
	TLOA J,CRBIT		;Flag LECD, ADJTB and INSTAB not to put out DM chars
	CAIN AC3,11		;YES. MORE THAN ONE SPACE ?
LEOVD:	PUSHJ P,LECDOV		;DELETE NEXT CHR. IN LINE.
	POP P,CHR		;NOW INSERT NEW ONE.
	TLOA J,NOBRBT		;FORCE REPOSITIONING OF THE LONG LINE CRLF
LEINS:	TLO J,DMHARD!NOBRBT	;Insertion is harder than overtyping
	PUSHJ P,CKMETA		;See if we should flush the META bit
	PUSHJ P,CKBITS		;See if this character is allowed to have bits
	PUSHJ P,PUTCHR		;PLACE NEW CHR. IN LINE.
	AOS FCPOS(J)		;INC. TOTAL CHR. COUNT.
TXINS:	MOVNI AC3,1(AC3)	;- NO. OF COLUMNS INSERTED.
	MOVE TAC1,LEPNT1(J)	;GET CURRENT POINTER.
	PUSHJ P,ADJTB		;GO FIDDLE NEXT TAB IN LINE.
	 JFCL
	TLZ J,CRBIT		;This may have been set for LECD, INSTAB, and ADJTB
	JRST LE2X

LEOVSC:	ILDB AC3,TAC		; PICK UP NEXT CHARACTER
	CAIE AC3,11		; IS IT THE FINAL TAB YET?
	JRST LEOVSC		; NO, LOOK SOME MORE
	JRST LEOVS		; YES, NOW LOOK AGAIN.

CKMETA:	CAIE UCHN,CBIT2		;INSERT VIA META?
	POPJ P,			;NO.
	MOVE AC1,XDEL		;GET X DIMENSION OF A CHR. (ARG TO INSP1)
	TLZE J,INSBT		;IF WE'RE IN INSERT MODE, WE LEAVE IT, ADJUSTING
	PUSHJ P,INSP1		;  THE III CURSOR POSITION.

;	MOVEI UCHN,		; DON'T LET IT ACTIVATE IN SPECIAL ACT MODE
;	PUSHJ P,SPCACT		; UNLESS IT WOULD'VE WITHOUT META
;	MOVEI UCHN,CBIT2

	MOVE AC1,SPCTAB(CHR)	;GET SPECIAL BITS FOR THIS CHAR
	CAIE CHR,15		;CR GETS TO KEEP ITS META BIT (ACTUALLY, LF GETS IT)
	TLNE AC1,BREAKB!FCSBRK	;IS IT ALWAYS A BREAK CHAR?
	POPJ P,			;YES, MAINTAIN META BIT (CR, LF, ALT, OR RUBOUT)
	MOVEI UCHN,0		;NO, DON'T LET IT KEEP THE META BIT
	TLNN DAT,SPCBRK		; UNLESS IT WOULD ACTIVATE ANYWAY
	POPJ P,			;WE'RE NOT IN SPECIAL ACTIVATION MODE
	PUSHJ P,SPCACT		;IS THIS CHAR A SPECIAL ACTIVATOR?
	 MOVEI UCHN,CBIT2	;YES, LET IT KEEP THE META BIT
	POPJ P,

↑CKBITS:JUMPLE UCHN,CPOPJ	;DON'T BOTHER IF NO BITS
	MOVE AC2,ACTMOD(DDB)	;GET SPECIAL MODE BITS
	HLL AC2,TTYTAB(DAT)
	TLNN AC2,COMBIT!DLYBIT	;IF ALREADY COMMAND WAITING, ASSUME NOT MONITOR MODE
	TLNN IOS,TPMON		;IN MONITOR MODE?
	TRNE AC2,SUPACT		;OR WANT TO SUPPRESS ACTIVATION AND BUCKY BITS?
	TRZA UCHN,-1		;YES, FLUSH ANY BUCKY BITS
	TRNN AC2,SUPSOM		;WANT TO SUPPRESS BUCKY BITS ON SOME CHARS?
	POPJ P,			;NOPE, LEAVE BITS ALONE
	MOVE AC2,UCHN		;SAVE BUCKY BITS
	HRRI UCHN,0		;ASSUME NO BUCKY BITS
	PUSHJ P,SPCACT
	 MOVE UCHN,AC2		;BIT ON IN TABLE, RESTORE BUCKY BITS
	POPJ P,
;PUTLF PUTCHR PUTCH2 PUTCH3 PUTCH1

;;SUBROUTINES FOR INSERTING CHARACTERS IN THE LINE.

PUTLF:	MOVEI CHR,12		;INVENT A LINE FEED.
	AOS FCPOS(J)
PUTCHR:	SETZB AC3,NUMARG(J)	;CLEAR REPEAT ARG.
	PUSHJ P,INSCHR		;PLACE CHAR. INTO LINE.
	CAIN CHR,11		;DID WE INSERT A TAB ?
	PUSHJ P,INSTAB		;YES.
	MOVE AC2,XDEL		;PREPARE TO MOVE CURSOR.
	ADDM AC2,LEPPV(J)	;MOVE CURSOR OVER ONE PLACE.
	AOS DSER,LEHPOS(J)
	CAILE DSER,=72		;ARE WE AT RIGHT SIDE OF SCREEN ?
	PUSHJ P,SHIFTL		;YES. SHIFT THE LINE LEFT SOME.
	AOS TAC,CCPOS(J)	;CURRENT POSITION IN CHARS.
	TLNE DAT,PTYLIN		;A PTY WITH XON ON GETS NO FREE LFS
	TLNN DAT,XON
	CAIE CHR,15		;IS IT A CR ?
	JRST .+2
	JRST PUTLF		;YES.
	SKIPE III(J)		; IS THIS A DD OR DM DISPLAY?
	POPJ P,			; NO, LEAVE NOW
	PUSH P,AC3		; SAVE NUMBER OF CHARACTERS INSERTED
	MOVE AC3,CURPP(J)
	MOVE AC1,PPHPOS(J)	;GET INITIAL X POSITION
	ADD AC1,LEHPOS(J)	; ADD IN LINE EDITOR'S HORIZONTAL POSITION
	CAIE CHR,11		; WAS THE CHARACTER A TAB?
	JRST PUTCH1		; NO, BREAK ONLY IF EVENLY AT END OF LINE
	TLNN DAT,DMLIN		; DM's line is exact multiple of tab size
	ADDI AC1,4		; CENTER TAB ON END OF SCREEN FOR DD
	IDIV AC1,LNLNGT(AC3)	; SEE IF WE ARE NEAR THE END OF THE LINE
	CAIG AC2,10		; WITHIN + OR - 4 CHARACTERS?
PUTCH2:	TLO J,NOBRBT		; YES, DO LINE BREAKING CALCULATION THIS TIME
PUTCH3:	POP P,AC3		; RESTORE NUMBER OF CHARACTERS INSERTED
	POPJ P,

PUTCH1:	SUBI AC1,1
	IDIV AC1,LNLNGT(AC3)	; SEE IF WE ARE EXACTLY AT THE END OF THE LINE
	JUMPE AC2,PUTCH2	; YES, BREAK OUR LINE THIS TIME
	JRST PUTCH3		; RESTORE ACCUMULATOR AND LEAVE
;INSTAB INST1 INST3 INST4 INST2 INSCHR INSCH1 LEINSW LEBGLP INSW1 LEPACK

INSTAB:	MOVEI CHR," "		;A TAB. PREPARE TO (SIGH) SIMULATE IT.
	MOVE AC1,LEHPOS(J)	;GET LINE EDITOR HPOS
	SKIPN III(J)
	ADD AC1,PPHPOS(J)	;MAKE IT ABSOLUTE ON DD--WHY? BECAUSE OF WRAPAROUND?
	ANDCAI AC1,7		;HOW MANY SPACES TO INSERT (LESS 1).
	ADDM AC1,LEHPOS(J)
	PUSH P,AC1		;REMEMBER THE MAGIC NUMBER
	SKIPA AC2,XDEL		;PREPARE TO MOVE CURSOR.
INST1:	ADDM AC2,LEPPV(J)	;MOVE CURSOR OVER ONE PLACE.
	PUSHJ P,INSCHR		;INSERT A SPACE IN THE LINE.
	SOJGE AC1,INST1		;BACK FOR MORE IF APPROPRIATE .
	TLNN DAT,DMLIN
	JRST INST2
	TLNE J,CRBIT		;Are we typing a tab over a tab?
	JRST INST4		;Yes, don't need to output spaces here on DM
	TLO J,DMHARD		;This case is sometimes hard since we insert spaces
	PUSH P,(P)		;Copy number of spaces being inserted minus one
	MOVEI CHR,ID
	PUSHJ P,QUODMX		;Enter ID mode
	MOVEI CHR,IDADDC
INST3:	PUSHJ P,QUODMX		;Insert a space
	SOSL (P)
	JRST INST3		;More
	MOVEI CHR,CANCEL
	PUSHJ P,QUODMX		;Leave ID mode
	SUB P,[1,,1]
INST4:	MOVEI CHR,LEMOVE
	PUSHJ P,QU2DMC		;Tell ttyser we want LE cursor moved
	MOVE CHR,(P)		;Number of spaces inserted minus one
	ADDI CHR,1		; plus one makes amount need to move cursor
	PUSHJ P,PUTDMC		;Put out low-order byte of cursor movement distance
	SETZ CHR,		;High-order byte is zero
	PUSHJ P,PUTDMC
INST2:	POP P,AC3		;Get back number of spaces inserted minus one
	MOVEI CHR,11		;NOW FINISH OFF WITH ANOTHER TAB.
INSCHR:	ILDB TAC,LEPNT1(J)	;LOOK AT NEXT CHR.
	JUMPE TAC,INSCH1	;IF NULL, PUT NEW CHR. ON TOP OF IT.
	MOVE TAC,LEPNT1(J)	;GET PTR.
	PUSHJ P,LEINSW		;INSERT A WORD OF NULLS.
INSCH1:	DPB CHR,LEPNT1(J)	;PUT NEW CHR. IN LINE.
	POPJ P,

LEINSW:	AOS DSER,LELWD(J)	;UPDATE PTR. TO RETURN JMP.
	CAILE DSER,MAXPT(J)	;MORE ROOM IN BUFFER ?
	PUSHJ P,GCOLL		;BUFFER NEARLY FULL, COMPRESS OUT ALL THE NULLS
	CAIGE DSER,LEBUF+BUFL-1(J) ;DON'T CLOBBER WORD AFTER LE BUFFER
	JRST INSW1
	PUSHACS
	PUSHJ P,DISGST		;PRINT TIME OF MESSAGE ON CTY
	PUSHJ P,DISERR
	[ASCIZ/Line editor garbage collect failed to get free space!  TTY/]
	DISARG LOC,<DAT-20(P)>
	[ASCIZ/
LETAB(DAT) = /]
	DISARG OCH,<LETAB(DAT)>
	[ASCIZ/   J = /]
	DISARG OCH,<J-20(P)>
	[ASCIZ/   Free = DSER = /]
	DISARG OCH,<DSER-20(P)>
	[ASCIZ/
LELWD(J) = /]
	DISARG OCH,<LELWD(J)>
	[ASCIZ/   LEPNT1(J) = /]
	DISARG OCH,<LEPNT1(J)>
	-1
	PUSHJ P,DISCRLF
	PUSHJ P,DISFLU
	POPACS
	PUSHJ P,WDDTCAL
LEBGLP:	HRRZ TAC,(P)		;GET RETURN ADDRESS
	SUB P,[1,,1]		;GET A RETURN ADDRESS FROM STACK
	CAIE TAC,KBDBCA+1	;IS THIS RETURN TO KBDED?
	JRST LEBGLP		;NO
	PUSHJ P,INITIT		;TRY TO CLEAN UP THE LINE EDITOR DATA
	HRRZS LETAB(DAT)	;CLEAR ALL THE FLAGS
	SETZM LEPNT1(J)		;PREVENT CONTROL-CR
	SETZM LEINV(J)
	POPJ P,			;YES, RETURN FROM KBDED ALTOGETHER, QUICKLY

INSW1:	MOVE TAC1,(DSER)	;GET WORD FROM BUFFER AND
	MOVEM TAC1,1(DSER)	;MOVE IT UP ONE.
	CAILE DSER,(TAC)	;ARE WE DOWN TO WHERE WE WILL INSERT THE NULLS ?
	SOJA DSER,INSW1		;NO.
	MOVEI DSER,0		;PREPARE TO INSERT NULLS.
	MOVE TAC1,TAC
	IDPB DSER,TAC1		;NULL NEXT CHAR. AFTER CURRENT ONE..
	IDPB DSER,TAC1		;..AND ALSO NEXT 3 AFTER THAT.
	IDPB DSER,TAC1
	IDPB DSER,TAC1
	TLZ J,TABB		;WE NO LONGER KNOW WHERE NEXT TAB IS.
	POPJ P,

;HERE FROM CONTROL-CR TO SHORTEN LONG LINE (CLOBBERS TAC, BOTH HERE AND IN GCOLL)
LEPACK:	AOS TAC,LELWD(J)	;UPDATE PTR. TO RETURN JMP (FOR GCOLL)
	CAILE TAC,MAXPT(J)	;SPARE ROOM IN BUFFER? (WE'RE NOT INSERTING A WD)
	PUSHJ P,GCOLL		;BUFFER NEARLY FULL, COMPRESS OUT ALL THE NULLS
	SOS TAC,LELWD(J)	;RESTORE POINTER TO LAST WORD OF TEXT IN BUFFER
	CAIG TAC,MAXPT-1(J)	;NOW HAVE ROOM IN BUFFER (WITH WORD TO SPARE)?
	POPJ P,			;YES, LINE EDITOR IS NOW SHORT ENOUGH
	PUSHJ P,CRKILL		;DELETE A CHAR FROM END OF LINE EDITOR
	JRST LEPACK		;AND CHECK AGAIN
;GCOLL GCOLL1 GCOLL3 PCHK GCOLL2 GCOLL4 GCOLL5

; THIS IS THE LINE EDITOR'S GARBAGE COLLECTOR. IT GOES THROUGH THE
; BUFFER AND COMPRESSES OUT ALL THE NULL CHARACTERS. IT MUST RESET THE
; POINTER TO THE LAST WORD IN THE TABLE, LELWD, MUST RESET THE BYTE POINTERS
; IN LEPNT1 AND IN TAC.

GCOLL:	PUSH P,AC1		; FIRST, SAVE A FEW ACCUMULATORS
	PUSH P,AC2
	PUSH P,AC3
	PUSH P,UUO
	MOVSI AC1,440700	; NOW MAKE UP TWO BYTE POINTERS TO THE BUFFER
	MOVSI AC2,440700
	HRRI AC1,LEBUF(J)
	HRRI AC2,LEBUF(J)
	SETZ AC3,		; THIS WILL BE THE COUNT OF THE NULLS WE SQUEEZED OUT
GCOLL1:	MOVE UUO,AC1		; NOW, TEST FOR END OF BUFFER
	IBP UUO			; SEE WHAT ADDRESS WE WOULD HAVE ENDED UP ON
	HRRZS UUO		; CLEAN IT UP
	CAML UUO,LELWD(J)	; COMPARE TO END OF BUFFER
	JRST GCOLL4
	ILDB UUO,AC1		; PICK UP FIRST CHARACTER IN LINE
	JUMPN UUO,GCOLL2	; IF NOT A NULL, JUST STUFF IT IN THE BUFFER
	ADDI AC3,1		; ANOTHER NULL, COUNT IT
GCOLL3:	PUSHJ P,PCHK		; UPDATE BYTE POINTERS IF NECESSARY
	JRST GCOLL1		; GO BACK FOR MORE

PCHK:	CAMN AC1,LEPNT1(J)	; ARE WE TO THE MAIN POINTER YET?
	MOVEM AC2,LEPNT1(J)	; YES, UPDATE IT
	CAMN AC1,TAC		; HAVE WE GOTTEN TO THE POINTER IN TAC YET?
	MOVEM AC2,TAC		; YES, UPDATE IT TOO
	POPJ P,

GCOLL2:	IDPB UUO,AC2		; PUT THE CHARACTER DOWN IN ITS NEW POSITION
	JRST GCOLL3		; GO BACK FOR MORE

GCOLL4:	PUSHJ P,PCHK		; UPDATE FINAL POINTER
	CAIGE AC3,5		; DID WE COLLECT A FULL WORD OF NULLS?
	TLO J,ACTNOW		; NO, ACTIVATE JOB NOW
	TDZA AC3,AC3		;FILL OUT REST OF WORD WITH NULLS
GCOLL5:	IDPB AC3,AC2
	TLNE AC2,760000		;HAVE WE USED UP THIS WORD OF 7-BIT BYTES?
	JRST GCOLL5		;NO, DEPOSIT A NULL
	MOVEI AC2,1(AC2)	; POINT FINAL POINTER TO LAST WORD IN BUFFER
	MOVE UUO,@LELWD(J)	; PICK UP RETURN JUMP
	MOVEM UUO,(AC2)		; PUT IT DOWN IN ITS NEW PLACE
	MOVEM AC2,LELWD(J)	; AND THIS IS THE NEW END OF BUFFER POINTER
	POP P,UUO		; RESTORE OUR ACCUMULATORS
	POP P,AC3
	POP P,AC2
	POP P,AC1
	POPJ P,
;LECT LECSP MVX1 MVX1A LECX LECX1 CKNFOR CKNFO2

;;ROUTINES TO PERFORM EDITING FUNCTIONS.

LECT:	MOVEI AC1,=200		;A CTRL TAB. SIMULATE 200 CTRL SPACES.
LECSP:	JSP TAC,CKNFOR		;CTRL SPACE. PREPARE TO MOVE CURSOR FORWARD.
	PUSHJ P,MOVEIT		;MOVE IT.
	 MVFOR			;MOVE FORWARD, PLEASE.
	TLO J,NOTEXT		; NOTE THAT WE HAVE ONLY CHANGED THE CURSOR POSITION, NOT THE TEXT
MVX1:	MOVEM TAC1,LEPNT1(J)	;UPDATE THE BYTE POINTER.
	PUSHJ P,DMMOVE		;Move cursor on DM
MVX1A:	MOVE DSER,AC2
	IMUL AC2,XDEL2		;CALC. AMOUNT TO MOVE CURSOR.
	LSH AC2,1		;THIS IS TO HANDLE OVERFLOW.
	PUSHJ P,SHIFT2		;UPDATE THE POSITION VECTOR
LECX:	TLZ J,SRCHBT!KILLBT	;MUST CLEAR KILLBT- NEEDED FOR CTRL-K
	SETZM NUMARG(J)
LECX1:	MOVE AC3,PRGNUM(J)	;Get display type bit
	TLNE AC3,DMLIN
	SKIPN DPHOLD(J)		;If holding on DM, Line editor goes on holding line
	SKIPA AC3,PPHPOS(J)
	MOVEI AC3,LDMSTR*5+1	;Column on holding line where DM LE goes if holding
	EXCH AC3,LSTHP(J)	; SEE THAT AS OUR NEW HORIZONTAL STARTING POSITION
	CAMN AC3,LSTHP(J)	; IS IT THE SAME AS LAST TIME
	TLZE J,NOBRBT		; OR HAS THIS LINE BEEN UNTOUCHED
	PUSHJ P,MAKECR		; VIRGIN LINE OR DIFFERENT HORIZONTAL POSITION
	TLNE J,ACTNOW		; DO WE HAVE TO ACTIVATE NOW?
	JRST ACTIV1		; YES, DO SO
	MOVE AC3,PRGNUM(J)	;Get tty line number
	HLLM J,LETAB(AC3)	;UPDATE THE STATUS BITS.
	POPJ P,

CKNFOR:	TLOE J,EOLBT		;AT END OF LINE ALREADY ?
	JRST LECX		;YES. CAN'T MOVE FORWARD.
CKNFO2:	ADD AC1,CCPOS(J)	;FIND POS. AFTER MOVE.
	CAMGE AC1,FCPOS(J)	;WILL MOVE TAKE US TO END OF LINE ?
	TLZA J,EOLBT		;NO. RESET FLAG SAYING WE ARE THERE.
	MOVE AC1,FCPOS(J)	;YES. DON'T LET IT TAKE US PAST END.
	EXCH AC1,CCPOS(J)	;PUT BACK NEW POSITION.
	SUB AC1,CCPOS(J)	;GET -NO. OF PLACES TO MOVE.
	JRST (TAC)		;RETURN.
;LECFF LEBS LEBS2 SRBAK2 BSP1 BSP2 BSP3 TXBSP DMMOVE MVX1C

LECFF:	MOVEI AC1,=200		;SIMULATE 200 CTRL BS'S
	MOVEM AC1,NUMARG(J)
LEBS:	CAIN UCHN,CBIT2!CBIT1
	JRST LEBSCK		;CTRL-META-BS MEANS REPEAT CONTROL-BS
LEBS2:	SKIPN CCPOS(J)		;BACKSPACE OR CTRL BACKSPACE.
	JRST LECX		;IGNORE BS AT START OF LINE.
	TRZE UCHN,CBIT2
	JRST .+3		;META-BS ALWAYS DELETES
	TLNN J,EOLBT!INSBT	;ARE WE AT END OF LINE OR IN INSERT MODE ?
	HRRI UCHN,10		;NO. FORCE NON-DELETING BS. (UCHN POSITIVE RH)
	MOVN AC1,NUMARG(J)	;- RPT. ARG.
SRBAK2:	ADDM AC1,CCPOS(J)	;POSITION AFTER MOVE.
	SKIPL AC2,CCPOS(J)	;WILL MOVE GO PAST START OF LINE 
	JRST BSP1		;NO.
	SUB AC1,AC2		;YES. RE-ADJUST CNT. SO IT WON'T.
	SETZM CCPOS(J)		;MARK AT BEGINNING OF LINE.
BSP1:	JUMPG UCHN,BSP3		;CTRL BITS ?
BSP2:	ADDM AC1,FCPOS(J)	;NO. WE WILL ACTUALLY DELETE CHRS.
	TLZ J,NOCRBT		;THIS IS FOR BENEFIT OF INIT4.
	TDZA CHR,CHR		;SET CHR TO 0 SO MOVEIT WILL DELETE.
BSP3:	TLZ J,EOLBT		;CTRL BACKSPACE. NO LONGER ARE WE AT END OF LINE.
	PUSHJ P,MOVEIT
	 MVBAK			;MOVE BACKWARD RIGHT AMOUNT.
	MOVNS DSER,AC2		;- NO. OF COLUMNS MOVED.
	TLO J,NOTEXT		; MARK CURSOR CHANGE ONLY
	JUMPG UCHN,MVX1		;IF NON-DELETING BACKSPACE, JUST UPDATE CURSOR AND LEAVE.
TXBSP:	TLZ J,NOTEXT		; AHA, TEXT IS CHANGED TOO!
	MOVEM TAC1,LEPNT1(J)
	PUSHJ P,DMMOVE		;Move cursor on DM and delete right number of chars
	PUSH P,AC2		;SAVE -NUMBER OF COLUMNS MOVED.
	PUSHJ P,ADJTB
	JFCL			;IGNORE SKIP RETURN
	POP P,AC2		;GET BACK NUMBER OF COLUMNS MOVED.
	JRST MVX1A

DMMOVE:	TLNN DAT,DMLIN
	POPJ P,			;Not Datamedia
	PUSH P,AC3
	PUSH P,AC2		;Save amount of movement
	PUSH P,CHR		;Remember whether we did any deleting
	MOVEI CHR,LEMOVE
	PUSHJ P,QU2DMC		;Put out quoted LEMOVE char, leaving room for 2 more
	LDB CHR,[POINT 7,-1(P),35] ;Get low-order bits of movement amount
	PUSHJ P,PUTDMC
	LDB CHR,[POINT 7,-1(P),28] ;Get high-order bits
	PUSHJ P,PUTDMC
	POP P,CHR
	JUMPN CHR,MVX1C		;Jump if just cursor movement needed
	MOVM AC2,(P)		;Number of columns to delete
	PUSHJ P,DMDELE		;Tell DM to delete some chars
MVX1C:	POP P,AC2
	POP P,AC3
	POPJ P,
;LECI ACTIVX INSP1 SRCHCR LECD LECDOV DMDELE DMDEL2 DMDEL3

LECI:	TLNN J,EOLBT		;Can't enter insert mode at end of line
	TLOE J,INSBT		;FLAG INSERT MODE.
	JRST LECX		;ALREADY IN THAT MODE !
	TLO J,NOTFR		; THIS IS A SILENT ONE
	PUSHJ P,LECX		;UPDATE STATUS WORD.
ACTIVX:	MOVN AC1,XDEL
INSP1:	ASH AC1,-1		;FOR INSERT MODE, WE MOVE CURSOR BY
	ADDM AC1,LEPPV(J)	; 1/2 A CHAR. WIDTH.
	LDB AC2,[POINT 11,LEPPV(J),21]
				;NOW THE Y POS.
	ASH AC1,-=26		;(MOVE IT BY 1/4 CHAR. WIDTH.)
	SUB AC2,AC1		;(MOVE IT IN OTHER DIRECTION,TOO.)
	DPB AC2,[POINT 11,LEPPV(J),21]
	POPJ P,

SRCHCR:	TLNN TAC,KILLBT		;ARE WE KILLING OR JUST MOVING?
	JRST LECT		;JUST MOVE TO END OF LINE
	MOVEI AC1,=200		;KILL TO END OF LINE
LECD:	TLO J,DMHARD		;This is a hard case if multi-line editor
LECDOV:	JSP TAC,CKNFOR		;CTRL D. PREPARE TO MOVE FORWARD.
	ADDM AC1,FCPOS(J)	;DECREMENT NO. OF CHRS. IN LINE.
	ADDM AC1,CCPOS(J)	;DON'T INCREMENT THE CURRENT POSITION.
	MOVEI CHR,0		;SET TO DELETE...
	PUSHJ P,MOVEIT		;MOVE FORWARD, DELETING.
	 MVFOR
	TLNE DAT,DMLIN
	TLNE J,CRBIT
	JRST ADJNTB		;Coming from LEOVD, don't diddle DM display
	PUSH P,AC3		;Save number of columns deleted for ADJNTB
	PUSHJ P,DMDELE		;Delete appropriate number of columns on DM
	POP P,AC3
	JRST ADJNTB		; ADJUST NEXT TAB  - CLEAR KILLBT FROM J

DMDELE:	CAIG AC2,=79		;If need to delete more than whole line,
	SKIPE NCRS(J)		; or if line previously wrapped around,
	JRST DMDEL2		; then redraw whole line
	TLNE J,EOLBT		;If we have deleted to eol, just erase to eol
	JRST DMDEL3
	PUSH P,AC2		;Save count
	MOVEI CHR,LEDELE
	PUSHJ P,QU2DMC		;Put out quoted LEDELE char, leaving room for 2 more
	POP P,CHR
	JRST PUTDMC		;Put out count of deletions to make

DMDEL2:	TLO J,DMDAMN		;We may need to move text from beginning of line 2
	POPJ P,			; to end of line 1--force redrawing of whole line

DMDEL3:	MOVEI CHR,EEOL
	JRST QUODMX
;LECTX

LECTX:	MOVE TAC,CCPOS(J)	;GET CURRENT POSITION
	CAIGE TAC,2		;ARE THERE 2 CHARS TO TRANSPOSE?
	JRST LECX		;NOPE, THIS IS A NO-OP
	MOVNI AC1,1		;DELETE A CHAR
	SETZB CHR,UCHN		;DELETION FLAG IN CHR, NO BUCKY BITS IN UCHN
	PUSHJ P,MOVEIT
	 MVBAK
	PUSH P,TAC		;THIS IS THE DELETED CHARACTER
	SOS CCPOS(J)
	MOVNI AC2,(AC2)
	PUSHJ P,TXBSP		;DO IT ON THE SCREEN
	MOVNI AC1,1		;DO IT AGAIN
	MOVEI CHR,0
	PUSHJ P,MOVEIT
	 MVBAK
	EXCH TAC,(P)		;GET RIGHTMORE CHARACTER
	PUSH P,TAC		;SAVE CHAR
	SOS CCPOS(J)
	MOVNI AC2,(AC2)
	PUSHJ P,TXBSP		;DO IT ON THE SCREEN
	POP P,CHR		;RETRIEVE CHAR
	PUSHJ P,PUTCHR		;HIT IT
	TLO J,DMHARD!NOBRBT	;INSERTIONS ARE SLIGHTLY HARDER THAN NORMAL
	PUSHJ P,TXINS		;FIX THE SCREEN
	POP P,CHR		;AND THE LEFTMORE ONE
	PUSHJ P,PUTCHR
	TLO J,NOBRBT		;FORCE RECALCULATION OF LONG LINE CRLF ON DDs
	JRST TXINS		;FIX THE SCREEN
;ADJNTB ADJTB LECD4A LECD6 LECD5 LECD5A

; THIS ROUTINE ADJUSTS THE NEXT TAB, AS GIVEN BY THE BYTE POINTER IN TAC.
; THE COUNT OF THE NUMBER OF COLUMNS THE LINE HAS BEEN MOVED BY IS IN AC3.

ADJNTB:	PUSHJ P,ADJTB		; ADJUST OUR TABS
	JRST LECX		; (CLEAR KILLBT FROM J)
	JRST LECX		; (CLEAR KILLBT FROM J)

ADJTB:	MOVN AC1,AC3		;MAKE IT NUMBER OF COLUMNS INSERTED
	ADDM AC1,NTABHP(J)	;FIX HORIZONTAL POSITION OF NEXT TAB
	TLNN J,TABB+NOTABB	;DO WE KNOW ABOUT NEXT TAB ?
	PUSHJ P,FNTAB		;NO. FIND OUT.
	TLNN J,TABB		;IS THERE ONE ?
	POPJ P,			;NO.
	ANDI AC3,7		;COUNT MOD 8 OF CHRS. DELETED.
	JUMPE AC3,CPOPJ		;NO CHANGE IF MULTIPLE OF 8.
	MOVE AC2,NTABCT(J)	;GET SIZE OF NEXT TAB.
	ADD AC2,AC3		;NEW SIZE OF NEXT TAB.
	MOVE TAC,NTABPT(J)	;PTR. TO LAST SPACE IN NEXT TAB.
	CAIG AC2,10		;IS NEW SIZE TOO BIG ?
	JRST LECD5		;NO. TAB NEEDS TO GROW.
	SUBI AC2,10
	EXCH AC2,NTABCT(J)	;YES. TAB MUST SHRINK.
	SUB AC2,NTABCT(J)	;FIND OUT HOW MUCH TO SHRINK IT.
	MOVEI AC3,100(AC2)	;Save count of deleted spaces for fixing on DM
	MOVEI AC1,0
LECD4A:	DPB AC1,TAC		;NULL ONE OF THE SPACES IN THIS TAB.
	ADD TAC,[XWD 70000,0]	;DECREMENT POINTER.
	JUMPG TAC,.+2
	SUB TAC,[XWD 430000,1]
	SOJG AC2,LECD4A
LECD6:	MOVEM TAC,NTABPT(J)	;STORE UPDATED PTR.
	TLNN J,CRBIT		;Suppressing DM output for easy case?
	TLNN DAT,DMLIN		;Or not a DM?
	POPJ P,			;Yes, forget it
	PUSH P,CHR
	PUSH P,AC3		;Save our count
	MOVEI CHR,LEFIXT	;Tell transmitter routine we want to fix a tab
	PUSHJ P,QU2DMC		;Put out quoted char, with room for 2 args
	POP P,CHR		;Get count back
	MOVE AC2,NTABHP(J)	;Get horizontal position of the tab needing fixing
	SUB AC2,LEHPOS(J)	;Find distance from cursor
	TRZE AC2,200		;Is distance too big for one 7-bit byte?
	IORI CHR,40		;Yes, flag xmitter routine with bit in count byte
	PUSHJ P,PUTDMC		;First arg is count + 100 if delete + 40 if big DX
	MOVEI CHR,(AC2)
	PUSHJ P,PUTDMC		;Second arg is horizontal offset of tab from cursor
	POP P,CHR
	POPJ P,

LECD5:	MOVEI AC1," "		;PREPARE TO MAKE TAB GROW.
	MOVEM AC2,NTABCT(J)	;STORE NEW SIZE.
	MOVE AC2,AC3		;Save count of inserted spaces in AC3 for fixing DM
LECD5A:	ILDB TAC1,TAC
	JUMPE TAC1,.+2		;IS THERE A NULL NEXT ?
	PUSHJ P,LEINSW		;NO. PUT SOME IN.
	DPB AC1,TAC		;ADD A SPACE.
	SOJG AC2,LECD5A
	JRST LECD6
;SEARCH RESRCH SRCHL GETEM GETEM0 GETEM1 GETEM2

SEARCH:	MOVEI TAC,(CHR)		;SAVE CHR. TO BE SEARCHED FOR.
	HLL TAC,J		;COPY KILLBT FROM J
	TLZ TAC,XTABBT		;MAKE SURE WE DON'T SET THE BACKWARDS BIT HERE
	IORM TAC,LESVCH(J)	;SAVE ARGUMENT FOR CTRL R
RESRCH:	MOVE TAC,LESVCH(J)	;GET ARG FROM CTRL R
	TLNE TAC,XTABBT		;Backward search/kill?
	JRST SRBACK		;Yes
	TLNE J,EOLBT
	JRST LECX		;Nothing can be found since we are at end of line
	MOVEI CHR,(TAC)
	CAIN CHR,15
	JRST SRCHCR		;MOVE OR KILL TO END OF LINE
	MOVEI AC1,1		;INITIALIZE REPEAT COUNT FOR LATER
	MOVE AC3,LEPNT1(J)	;MAKE COPY OF CURRENT POINTER.
	MOVEI TAC1,AC3		;PARAMETER FOR GETEM.
	PUSHJ P,GETEM		;SKIP OVER CURRENT CHR. BEFORE STARTING SEARCH.
SRCHL:	PUSHJ P,GETEM		;GET NEXT CHR. FROM LINE.
	CAIN CHR,EOLCHR		;ARE WE AT END OF LINE ?
	JRST LECX		;YES. DO NOTHING, CHR. NOT FOUND.
	CAIN CHR,(TAC)		;HAVE WE FOUND IT ?
	SOSLE NUMARG(J)		;YES. IS THE REPEAT COUNT EXHAUSTED ?
	AOJA AC1,SRCHL		;NO. COUNT PLACES MOVED AND LOOK SOME MORE.
	TLNN TAC,KILLBT		;YES.  ARE WE KILLING OR JUST MOVING UP TO IT ?
	JRST LECSP		;MOVEING.
	JRST LECD		;KILLING.

GETEM:	ILDB CHR,(TAC1)		;GET A NON-NULL CHAR. FROM LINE.
GETEM0:	JUMPE CHR,.-1
	CAIN CHR,11		;IS IT A TAB ?
	TLCN J,XTABBT		;YUP. ALREADY INSIDE A TAB ?
	TLNN J,XTABBT		;INSIDE A TAB ?
	JRST GETEM1		; NO, EXIT
	CAIE CHR,11		; ARE WE INSIDE A CRLF?
	CAIN CHR," "
	JRST GETEM2		; NO. PASS OVER THE TAB.
	TLO J,CRBIT		; YES, MARK THIS AS A LONG LINE CRLF
	JRST GETEM		; LOOP BACK FOR NEXT CHARACTER

GETEM1:	TLZE J,CRBIT		; ARE WE COMING OUT OF A CRLF?
	JRST GETEM		; YES, GET NEXT CHARACTER PAST IT
	POPJ P,			; NO

GETEM2:	TLZ J,CRBIT
	JRST GETEM
;SRBACK SRBAKL SRBKCR GETLFT GETLF3 GETLF0 GETLF1 GETLF2

;Here to search or kill backwards (to the left)
SRBACK:	MOVN AC1,CCPOS(J)	;Do this much moving/killing if arg is CR
	JUMPGE AC1,LECX		;Jump if nothing to left in line editor
	MOVEI CHR,(TAC)
	CAIN CHR,15		;Is arg CR?
	JRST SRBKCR		;Yes, move or kill to beginning of line
	MOVE AC2,AC1		;Maximum amount of movement
	MOVE AC3,LEPNT1(J)	;MAKE COPY OF CURRENT POINTER.
	IBP AC3			;Point to current char so we can back up from there
	MOVEI TAC1,AC3		;PARAMETER FOR GETLFT
	MOVNI AC1,1		;Initialize movement amount
	TLNN TAC,KILLBT
	TDZA AC1,AC1		;Don't skip first char to left if just searching
	PUSHJ P,GETLFT		;Skip over first char to the left
SRBAKL:	CAMGE AC1,AC2		;Have we reached beginning of line?
	JRST LECX		;Yes, didn't find it
	PUSHJ P,GETLFT		;GET PREVIOUS CHR FROM LINE.
	CAIN CHR,(TAC)		;HAVE WE FOUND IT ?
	SOSLE NUMARG(J)		;YES. IS THE REPEAT COUNT EXHAUSTED ?
	SOJA AC1,SRBAKL		;NO. COUNT PLACES MOVED AND LOOK SOME MORE.
SRBKCR:	SETZ UCHN,		;ASSUME KILLING
	TLNE TAC,KILLBT		;YES.  ARE WE KILLING OR JUST MOVING UP TO IT ?
	JRST SRBAK2		;KILL EVERYTHING BETWEEN CURRENT CHAR AND ONE FOUND
	MOVEI UCHN,10		;MOVING
	SOJA AC1,SRBAK2		;END UP UNDER CHARACTER FOUND

GETLFT:	MOVSI CHR,70000
	ADDB CHR,(TAC1)		;BACK UP A BYTE
	JUMPGE CHR,GETLF3
	MOVN CHR,[430000,,1]
	ADDM CHR,(TAC1)		;BACK BYTE POINTER UP INTO PREVIOUS WORD
GETLF3:	LDB CHR,(TAC1)		;GET A NON-NULL CHAR. FROM LINE.
GETLF0:	JUMPE CHR,GETLFT
	CAIN CHR,11		;IS IT A TAB ?
	TLCN J,XTABBT		;YUP. ALREADY INSIDE A TAB ?
	TLNN J,XTABBT		;INSIDE A TAB ?
	JRST GETLF1		; NO, EXIT
	CAIE CHR,11		; ARE WE INSIDE A CRLF?
	CAIN CHR," "
	JRST GETLF2		; NO. PASS OVER THE TAB.
	TLO J,CRBIT		; YES, MARK THIS AS A LONG LINE CRLF
	JRST GETLFT		; LOOP BACK FOR NEXT CHARACTER

GETLF1:	TLZE J,CRBIT		; ARE WE COMING OUT OF A CRLF?
	JRST GETLFT		; YES, GET NEXT CHARACTER PAST IT
	POPJ P,

GETLF2:	TLZ J,CRBIT
	JRST GETLFT
;LEDESC ESCR ESCP ESCZ

LEDESC:	CAIN CHR,10044
	JRST CLEAR		; CLEAR LE OR UNHOLD PP
	CAIN CHR,10041
	JRST CTLBRK		; HOLD PP OUTPUT
	CAIN DSER,"-"		;ESC CONTROL-MINUS-SIGN IS HOLD (FOR DM W/WAITS KBD)
	JRST CKHOLD		;BREAK " IS UNHOLD FOR GENERALITY
	TLO J,NOTFR		; THIS IS A SILENT TRANSFER
	CAIL DSER,"a"
	CAILE DSER,"z"
	CAIA
	TRZ DSER,40		; CHANGE LOWER TO UPPER CASE
	CAIN DSER,"O"
	JRST ESCO
	CAIN DSER,"R"		; REFRESH HIS LINE EDITOR?
	JRST ESCR		; YES
	CAIN DSER,15
	JRST ESCCR		;ESC n CR is special
	PUSHJ P,TTYESC
	JRST LECX1

ESCR:	SKIPN III(J)		; DON'T REFRESH IF ON A III
	TLZ J,NOTEXT!NOTFR	; QUEUE UP A COMBINED TEXT AND CURSOR TRANSFER
	TLO J,DMDAMN		;Force out whole DM LE
	JRST LECX1

ESCP:	JUMPL AC1,BRKP		;<BREAK>P DOES THE WORKS
	HRLI AC2,LERFP		; USE THE MAGIC CLOCK LEVEL ROUTINE FOR REFRESHING THE PAGE
	JRST ESCC1

;ESC Z MEANS BEEP WHEN JOB IS DONE AFTER LONG WAIT, BREAK Z MEANS DON'T
↑ESCZ:	LDB AC2,PJOBN		;GET JOB NUMBER OF THIS GUY
	JUMPE AC2,CPOPJ		;IF YOU'RE NOT LOGGED IN, I CAN'T HELP YOU
	ROT AC1,1		;PUT SIGN BIT INTO LOW-ORDER BIT
	TRC AC1,1		;MAKE SIGN BIT ON MEAN CLEAR SIGN BIT OF JBTMSC
	DPB AC1,[POINT 1,JBTMSC(AC2),0] ;SET OR CLEAR SIGN BIT OF JBTMSC AS FLAG
	POPJ P,
;TTYESC

;HERE ARE THE ESCAPES THAT CAN BE CALLED FROM TTYSET UUO, WHICH IN FACT ENTERS HERE
↑TTYESC:
;The first few escapes can be executed for any TTY, whether a display or not.
	CAIN DSER,"Z"
	JRST ESCZ		;SIGNAL USER WHEN JOB DONE AFTER CERTAIN TIME
	CAIN DSER,"F"
	JRST ESCF		;YES. GO SEE ABOUT FCS MODE.
	CAIN DSER,"I"
	JRST ESCI
	CAIN DSER,"X"
	JRST ESCX		;SET OR CLEAR UPDATE BIT IN JBTMSC FOR THIS JOB
	CAIN DSER,"H"
	JRST ESCH		;SET OR CLEAR HIDDEN BIT
	CAIN DSER,"V"
	JRST ESCV		;FORCE FILES COMMAND (IN TTYSER)
	CAIN DSER,"."
	JRST ESCDOT		;FORCE TTY TO OR FROM MONITOR MODE (TPMON)
	JUMPE J,CPOPJ		;JUMP IF FROM TTYSET AND NO DISPLAY
;The remaining escape commands require you to be on a display.
	CAIN DSER,"W"
	JRST ESCW
	CAIN DSER,14
	JRST ESCFF		;Clear display screen
	CAIN DSER,"Q"
	JRST ESCQ		;GET WHO LINE FOR NEXT JOB WITH SAME PROG NAME
	CAIN DSER,"G"
	JRST ESCG
	CAIN DSER,"L"
	JRST ESCL
	CAIN DSER,"Y"
	JRST ESCY
	CAIN DSER,"N"
	JRST ESCN
	CAIN DSER,"E"
	JRST ESCE
	CAIN DSER,"J"
	JRST ESCJ
	CAIN DSER,"C"		; CLEAR SCREEN?
	JRST ESCC		; YES, GO QUEUE UP AN ERASE REQUEST
	CAIN DSER,"P"		; REFRESH HIS PAGE PRINTER?
	JRST ESCP		; YES, GO QUEUE UP A PAGE PRINTER REQUEST
IFN FTRANGE,<
	CAIN DSER,"<"
	JRST ESCLT
	CAIN DSER,">"
	JRST ESCGT
>;FTRANGE
	POPJ P,
;CLEAR CLEARL LECRLF LECLR2 MCLEAR ESCCR1 ESCCR

CLEAR:	CAIN UCHN,CBIT1		; <CTRL>CLEAR?
	JRST ESCU		; YES, UNHOLD
	JUMPN UCHN,MCLEAR	; NO, JUST FLUSH LINE UNLESS IT'S GOT <META>
	;FALL THROUGH INTO REAL CLEAR CODE
; THIS ROUTINE CLEARS THE LINE EDITOR BUFFER WITHOUT DISTURBING
; ITS STATUS. THIS MEANS THAT THE INFORMATION AS TO WHETHER
; THIS IS A RE-EDITED LINE IS PRESERVED.
CLEARL:	JUMPGE J,CPOPJ		;NOTHING TO CLEAR
	TLNE J,WTFLAG		;ESCAPES AVOID THIS TEST FOR WAIT FLAG
	JRST TPOPJ		; BUT WE BETTER NOT DO ANYTHING NOW
	PUSHJ P,LECRLF		;PUT CRLF ON END OF LINE EDITOR FOR BENEFIT OF αCR
	TLZ J,¬REEDBT		;CLEAR ALL THE BITS BUT THAT INDICATING REEDITED LINE
	TLO J,DMDAMN!NOCRBT	;NOCRBT means we have done a CLEAR not an ACTIV1
	PUSH P,LEPNT1(J)
	PUSHJ P,INIT3		;RESET MOST STUFF, STORE LH(J) IN LETAB
	POP P,LEPNT1(J)
	MOVEI TAC,LEB(J)
	HRLI TAC,DISJMP
	MOVSM TAC,LEPPV(J)	;DON'T DISPLAY THE BUFFER ON IIIS
	POPJ P,			;NOW CTRL-CR WILL UNDO THE CLEAR, UNLESS SUPPRESSED

;HERE FROM CLEAR AND CALL TO PUT CRLF ON END OF LINE EDITOR BEING FLUSHED.
LECRLF:	MOVEI AC1,=200
	JSP TAC,CKNFO2		;PREPARE TO MOVE FORWARD 200 CHARS
	MOVEI CHR,15		;MAKE MOVEIT NOT DELETE, PREPARE TO PUT CR AT EOL
	JUMPGE AC1,LECLR2	;JUMP IF ALREADY AT EOL
	PUSHJ P,MOVEIT		;MOVE TO EOL
	 MVFOR			;ARG TO MOVEIT
	MOVEM TAC1,LEPNT1(J)	;STORE NEW BYTE POINTER
LECLR2:	PUSHJ P,INSCHR		;INSERT A CR
	MOVEI CHR,12		;DON'T YOU HATE TYPING CR AND NOT GETTING THE CRLF?
	PUSHJ P,INSCHR		;INSERT A LF
	MOVEI CHR,2
	ADDM CHR,FCPOS(J)	;COUNT THE CR AND LF
	POPJ P,

MCLEAR:	CAIN UCHN,CBIT2
	TLNN DAT,DMLIN		;META-CLEAR ON DM (EDIT-CLEAR) FLUSHES ALL QUEUES
	POPJ P,
ESCCR1:	HRLI AC2,LEPDM4		;CLOCK LEVEL ROUTINE TO FLUSH QUEUES
	JRST ESCC1

;HERE FOR ESC n CR.
ESCCR:	CAIN AC1,1
	TLNN DAT,DMLIN		;ESC 1 CR ON DM FLUSHES OUTPUT QUEUES
	POPJ P,			;But no other ESC n CR cmds are defined yet.
	JRST ESCCR1
;ESCC ESCC0 ESCC1 ESCC2 BRKP ESCG ESCL CKHOLD CTLBRK ESCLT ESCGT ESCGT2

; WE GET HERE IF THE LOSER TYPES <ESC>C OR <ESC>¬C WHICH CAUSES
; HIS SCREEN (IF HE IS A DATA DISC TYPE) TO GET ERASED TO BLACK OR
; WHITE RESPECTIVLY.

ESCC:	SKIPE III(J)
	JRST ESCC0
	HRRZ AC2,CURPP(J)	; PICK UP PAGE PRINTER CONTROL BLOCK ADDRESS
;;	MOVSI AC3,(1B5)		; PICK UP BLACK BIT
;;	JUMPL AC1,.+3
;;	ORM AC3,DDCW(AC2)
;;	JRST .+2
;;	ANDCAM AC3,DDCW(AC2)
	ROT AC1,1		;Put sign bit into low-order bit
IFN FTDD,<
	TRC AC1,1		;Make BREAK (negative) clear the bit for DD
>;IFN FTDD
	DPB AC1,PBAKCL		;Store in page printer cmd word (AC2)
ESCC0:	MOVSI AC2,LEERS		; USE CLOCK LEVEL ROUTINE IN DPYSER THAT QUEUES IT UP
ESCC1:	HRRI AC2,(J)		; PUT IN THE DPY PROGRAM HEADER ADDRESS
ESCC2:	CONSZ PI,77000		;IN PROGRESS ON 1-6?
	JRST AC2CLK		;YES, PLANT CLOCK REQUEST THAT'S IN AC2
	PUSHACS			;NO, CALL ROUTINE NOW (UUO LEVEL OR CLK LEVEL)
	MOVE DAT,AC2		;ROUTINE EXPECTS DATUM IN DAT
	HLRZ AC2,AC2		;ROUTINE ADDRESS
	PUSHJ P,(AC2)		;CALL CLOCK LEVEL ROUTINE NOW INSTEAD OF LATER
	POPACS
	POPJ P,

BRKP:	HRLI AC2,RFPCS		; <BREAK>P CLEARS THE SCREEN AND REFRESHES BOTH
	JRST ESCC1		;    THE PAGE PRINTER AND THE LINE EDITOR.

ESCG:	HRLI AC2,PPGSET		; ROUTINE TO SET PAGE PRINTER GLITCHES/PAGE
	JRST ESCY1

ESCL:	HRLI AC2,PPLSET		; LINES/GLITCH
	JRST ESCY1

CKHOLD:	JUMPL AC1,ESCU		;JUMP IF BREAK α"-", WHICH MEANS UNHOLD
CTLBRK:	HRROS DPHOLD(J)		; PUT PAGE PRINTER IN HOLD
	TLNN DAT,DMLIN
	JRST LECX1
	MOVE AC2,DAT		;Line number for DPYTYP
	HRLI AC2,DPYTYP
	HRRZ AC1,DMPPPT(J)	;If anything in PP queue,
	CAIE AC1,DMPPPT-QLINK(J); then plant clock request for DPYTYP
	PUSHJ P,ESCC2		; to force out stars (thru LE queue).
	JRST LECX1

IFN FTRANGE,<
ESCLT:	MOVEM AC1,DMBEG(J)
	POPJ P,

ESCGT:	JUMPN AC1,.+2
↑ESCGT2:MOVEI AC1,-1		;This ought to be a big enough range
	MOVEM AC1,DMEND(J)
	POPJ P,
>;FTRANGE
;ESCJ ESCE ESCU ESCY ESCY1 ESCN ESCFF

ESCJ:	DPB AC1,[POINT 9,GWORD(J),26]	; SET NUMBER OF GLITCHES BEFORE HOLD
	MOVEM AC1,GLHCNT(J)
	TRNN AC1,-1
	SETOM GLHCNT(J)
	POPJ P,

ESCE:	DPB AC1,[POINT 9,GWORD(J),17]	; SET NUMBER OF LINES BEFORE HOLD
	JUMPG AC1,.+2		;JUMP UNLESS DISABLING AUTO HOLDING
	MOVSI AC1,377777	;MAKE A LARGE COUNT NEVER TO REACH ZERO
	MOVEM AC1,LHCNT(J)	;STORE COUNTDOWN TO NEXT AUTO HOLD
	POPJ P,

ESCU:	SETZ AC1,		; ROUTINE TO UNHOLD THE PAGE PRINTER
	EXCH AC1,DPHOLD(J)
	JUMPE AC1,LECX1
	HRRZ AC2,PRGNUM(J)
	HRLI AC2,UNHOLD
	PUSHJ P,ESCC2
	JRST LECX1

ESCY:	HRLI AC2,PPYSET		; ROUTINE TO SET Y-POSITION
	SKIPN GOTARG		;ANY ARGUMENT?
	MOVEI AC1,YLINE		;NO, USE DEFAULT Y-POSITION
ESCY1:	HRRZM AC1,LEARG(J)
	JRST ESCC1

ESCN:	MOVE DSER,AC1		; NORMALIZE PAGE PRINTER
IFE FTF2,<
	PUSHJ P,VDESCN		;NORMALIZE VDS ON DD (NO-OP IF NOT DD)
>;IFE FTF2
	MOVSI AC2,LEERSN
	JUMPL DSER,ESCC1
	MOVSI AC2,PPNSET
	JRST ESCC1

ESCFF:	JUMPL AC1,CPOPJ		;BREAK FORM DISALLOWED TO AVOID ACCIDENTS
	HRLI AC2,LECLRS		;ROUTINE TO CLEAR SCREEN BY GLITCHING
	JRST ESCC1
;ESCH ESCO ESCDOX ESCF ESCDOT ESCDO4 ESCDO2 ESCDO3 ESCDO6 ESCDOC ESCDOM

;SET OR CLEAR TERMINAL HIDDEN BIT
↑ESCH:	ROTC AC1,1		;SIGN BIT DOWN TO LOW-ORDER POSITION OF AC2
	TRC AC2,1		;BREAK H MEANS CLEAR THE BIT
	DPB AC2,[PHIDDN+DAT,,LSTESC] ;SET OR CLEAR HIDDEN BIT
IFE FTF2,<
	JUMPE J,CPOPJ		;JUMP IF NOT DISPLAY
	HLRZ AC1,PRGNUM(J)	;GET DD CHANNEL NUMBER OR BIT FOR DISPLAY TYPE
	TRNE AC1,DISLIN!DMLIN	;SKIP IF DD
	POPJ P,			;NOT DD
	DPB AC2,[DDPRVT+AC1,,DDTAB] ;SET OR CLEAR DD CHANNEL'S PRIVATE BIT
	JUMPN AC2,DDFLSH	;FLUSH SPIES FROM HIDDEN DD CHANNEL
>;IFE FTF2
	POPJ P,

ESCO:	MOVEI IOS,IOSUPR	;ASSUME AN UN-↑O.
	ANDCAB IOS,DEVIOS(DDB)
	JUMPL AC1,LECX1
	PUSHJ P,LECX1		;GET STATUS BITS STORED AND RESET.
	PUSH P,J		; SAVE THE DPY PROGRAM HEADER
	PUSHJ P,CONTOB		; DO A ↑O.
ESCDOX:	PUSHJ P,UTYPET		;AND MAKE SURE IT GETS OUT
	POP P,J
	POPJ P,

↑ESCF:	JUMPL AC1,.+2
	TLOA DAT,FCS		;TURN ON THE ↑F BIT (FULL CHR. SET).
	TLZ DAT,FCS		;WRONG. TURN IT OFF.
	HLLM DAT,LINTAB(DAT)
	POPJ P,

;HERE FOR ESC/BRK . TO DIDDLE TPMON BIT, TO PUT TTY INTO OR OUT OF MONITOR MODE.
;ANY NUMERIC ARG SUPPRESSES NORMAL CLEARING OF TTY INPUT BUFFER AND LINE EDITOR.
↑ESCDOT:JUMPL AC1,ESCDO2	;JUMP IF BREAK DOT
	TLNN IOS,TPMON		;ESC DOT -- MAYBE ALREADY IN MONITOR MODE
	JRST ESCDO3		;PLANT CLOCK REQ
ESCDO4:	SKIPE GOTARG		;ANY ARGUMENT SUPPRESSES CLEARING INPUT BUF/LE
	POPJ P,			;NUMERIC ARG GIVEN
	PUSH P,J		;PRESERVE DPY HDR
	PUSH P,DAT		;PRESERVE LINE NUMBER
	PUSHJ P,SETBFT		;CLEAR INPUT BUFFER (DOESN'T CALL LINED)
	POP P,DAT
	POP P,J
	TLZ J,NOTFR		;NOT SILENT TRANSFER IF CLEARING ANY LINE EDITOR
	JRST CLEARL		;CLEAR LINE EDITOR, IF ANY

ESCDO2:	TLNN IOS,TPMON		;BREAK DOT -- MAYBE ALREADY OUT OF MONITOR MODE
	JRST ESCDO4		;YES, JUST CLEAR INPUT BUFFER AND LINE EDITOR
ESCDO3:	MOVSI AC2,ESCDOC	;USE CLOCK LEVEL ROUTINE, MAKE SURE JOB IS STABLE
	HRRI AC2,(DAT)		;LINE NUMBER IS DATUM
	TLNE AC1,400000		;IF ESCAPE, DON'T SET BREAK BIT FOR CLK REQ
	TRO AC2,400000		;FLAG BREAK COMMAND
	PUSH P,AC2		;PRESERVE CLK REQ WORD
	PUSHJ P,ESCDO4		;CLEAR TTY INPUT BUFFER AND LINE EDITOR, IF ANY
	POP P,AC2
	JRST ESCC2		;PLANT CLOCK REQUEST

;Here at clock level for ESC . to put TTY into monitor mode.  Scanner is off.
ESCDO6:	TLNE IOS,TPMON		;MAYBE ALREADY IN MONITOR MODE
	JRST SCNONJ		;YUP, NOTHING TO DO
	MOVSI IOS,TPMON		;PUT US INTO MONITOR MODE
	IORM IOS,DEVIOS(DDB)
	MOVSI IOS,DDTM!SNKWAT
	ANDCAB IOS,DEVIOS(DDB)	;TURN OFF WAIT BITS WHEN GOING TO MONITOR MODE
	PUSHJ P,ESCDOM		;FLUSH REMAINDER OF MONITOR COMMAND, TYPE CRLF
	JRST PRPER		;POPJ INTO ROUTINE TO PRINT A PERIOD

;HERE AT CLOCK LEVEL TO SWITCH TTY TO USER MODE
ESCDOC:	HRLZ AC1,DAT		;SAVE THE ESCAPE/BREAK FLAG
	ANDI DAT,377777		;CLEAR FLAG, LEAVING ONLY LINE NUMBER
	CAIGE DAT,TTPLEN	;LEGAL LINE NUMBER?
	SKIPN DDB,TTYTAB(DAT)	;YES, GET TTY DDB
	POPJ P,			;NONE!
	OFFSCN			;DON'T LET TPMON CHANGE FROM UNDER US
	MOVE TAC,DEVMOD(DDB)
	TLNN TAC,TTYATC		;MAKE SURE TTY REALLY ATTACHED TO JOB
	JRST SCNONJ		;FORGET IT
	MOVE IOS,DEVIOS(DDB)
	JUMPGE AC1,ESCDO6	;JUMP IF ESCAPE (AS OPPOSED TO BREAK)
	LDB J,PJOBN		;BETTER HAVE A JOB THAT'S NOT STOPPED
	JUMPE J,SCNONJ
	MOVM TAC,JOBQUE(J)	;SEE WHAT QUEUE THE JOB IS IN
	CAIE TAC,NULQ
	CAIN TAC,STOPQ
	JRST SCNONJ		;USER MODE TTY IS SILLY IF JOB STOPPED
	TLNN IOS,TPMON		;MAYBE WE'RE ALREADY OUT OF MONITOR MODE
	JRST SCNONJ		;FORGET IT
	MOVSI IOS,TPMON
	ANDCAB IOS,DEVIOS(DDB)	;TURN OFF TPMON
	JUMPGE IOS,ESCDOM	;JUMP IF NOT WAITING FOR TTY INPUT
	MOVSI IOS,DDTM!SNKWAT	;GET REMEMBERED TTY WAIT STATE, IF ANY
	AND IOS,TTYBTS(DDB)
	IORB IOS,DEVIOS(DDB)	;RESTORE REMEMBERED STATE
ESCDOM:	ONSCN
IFN FTMONCIP,<
	PUSHJ P,MCMSKP		;SKIP REST OF ANY MONITOR CMD LEFT IN BUFFER
>;IFN FTMONCIP
	PUSHJ P,TYCRLF		;TYPE OUT A CRLF
	PUSH P,J		;PRESERVE DPY HDR (IF ANY)
	JRST ESCDOX		;START TYPEOUT AND RESTORE J
;ESCV ESCW ESCW0 ESCW3 ESCW2 ESCW1 NXTWHO ESCQ ESCQY ESCQX

ESCV:	PUSH P,J		;SAVE DPY HDR
	MOVEI J,0		;FLAG ESCW TO JUMP BACK TO FORCE CMD
	PUSHJ P,BNFILE		;THIS SETS UP TAC TO F.FILE AND GOES TO ESCW
	POP P,J			;RESTORE DPY HDR
	POPJ P,

;BNWHO DEPENDS ON THIS CODE (DOWN TO NXTWHO) NOT CLOBBERING TAC

↑ESCW:	SKIPN GOTARG		;ANY ARGUMENT?
	JRST ESCW0		;NO
	JUMPL AC1,ESCW3		;BREAK # W--GET WHOLINE FOR TTY #
	JUMPG AC1,ESCW1	;ESC # W--GET WHOLINE FOR JOB #
	JUMPE J,CPOPJ		;↑← 0 W -- TYPE SYSTEM WHOLINE
	JRST REWHO		;ESC 0 W--REDRAW WHOLINE

ESCW0:	JUMPGE AC1,ESCW1	;ESC W--TURN ON OUR WHOLINE
	JUMPE J,CPOPJ		;DO NOTHING ON ↑← - W
	SETZM WHOTAB(J)		;BRK W--TURN OFF WHOLINE
	POPJ P,

ESCW3:	ANDI AC1,-1		;Just the arg here, discard sign
	SKIPN TAC1,PHYLIN	;Get typer's actual terminal number
	MOVE TAC1,DAT		;Must be PTY, get LINED's version of line number
	PUSHJ P,ESCOCT		;Convert to octal and remember typer's repeat arg
	CAIGE AC1,TTPLEN	;Illegal tty number?
	SKIPN AC1,TTYTAB(AC1)	;or no DDB?
	JRST [	MOVNI AC1,1 	;YES, NO-OP
		POPJ P,]
	LDB AC1,[POINT JOBNSZ,DEVJBN(AC1),JOBNPS] ;Get job number of tty's owner
	JUMPN AC1,ESCW1		;Any job there?
	POPJ P,			;No, no wholine

ESCW2:	TLZ AC1,-1		;THIS IS WHERE [ESC] # Q DOES [ESC] # W
ESCW1:	TRNN AC1,-1
	LDB AC1,PJOBN		;GET JOB NUMBER OUT OF DDB IF NO ARGUMENT.
	MOVSI AC2,JNA
	CAIGE AC1,JOBN		;LEGAL JOB NUMBER?
	TDNN AC2,JBTSTS(AC1)	;YES, IS IT LOGGED IN?
	POPJ P,			;NO JOB, IGNORE ESC # W
NXTWHO:	JUMPE J,CPOPJ		;JUMP IF HERE FOR ↑←W COMMAND
	HRROM AC1,WHOTAB(J)	;YES, STORE JOB #.  ALSO PUT -1 IN INCR TIME SLOT.
	SETZM WHORUN(J)		;CLEAR TIME TO UPDATE RUNTIME NEXT
	TLNN DAT,DDDLIN!DMLIN	;This would be useless for IIIs anyway
	POPJ P,
	TLNN DAT,DDDLIN
	SKIPA AC1,[-LDMWQ,,DMWQ]
	MOVE AC1,[-LDDWQ,,DDWQ]
	SKIPE (AC1)
	AOBJN AC1,.-1
	JUMPGE AC1,CPOPJ
	HRRZ AC2,PRGNUM(J)	;Line number
	HRROM AC2,(AC1)		;Pass it to WHOSER as an extra wholine to do
	MOVEI AC2,DMWHO(J)	;Pointer to wholine queue if this is DM
	TLNE DAT,DMLIN
	PUSHJ P,DMFLUS		;Flush any DM wholine in progress
	POPJ P,

ESCQ:	TRNE AC1,-1		;ANY ARGUMENT?
	JRST ESCW2		;[ESC] # Q AND [BRK] # Q ARE SAME AS [ESC] # W
	MOVEI AC3,1		;ASSUME POSITIVE INCREMENT FOR GOING THRU TABLE
	JUMPGE AC1,.+2		; UNLESS HE SAID [BRK] Q
	MOVNI AC3,1		; IN WHICH CASE WE USE NEGATIVE INCREMENT
	SKIPN AC1,WHOTAB(J)	;GET NUMBER OF JOB ON WHO LINE
	LDB AC1,PJOBN		;NO WHO LINE.  USE USER'S JOB.
	ANDI AC1,-1		;MAKE SURE TAC HAS ONLY THE JOB NUMBER
	JUMPE AC1,CPOPJ		;IF NOT LOGGED IN AND NO WHO LINE UP, FORGET IT
	HRRZ AC2,PRJPRG(AC1)	;GET PROGRAMMER NAME OF OLD WHO LINE JOB
	PUSHJ P,ESCQY
	POPJ P,			;NOTHING FOUND
	SKIPN TAC1,PHYLIN	;Physical line number for next three DPBs
	JRST NXTWHO
	DPB AC1,NUMESC		;This is so that ESC * will redraw the same
	MOVEI AC2,0		; wholine we are just now setting up.
	DPB AC2,SGNESC
	MOVEI AC2,"W"
	DPB AC2,CHRESC		;Pretend he typed ESC n W with proper job number n
	JRST NXTWHO		;Tell WHOSER to do it, and to do it now

;CALLED FROM VDESCM CODE IN TTYSER.  
;AC2←PRG NAME. AC3←DIRECTION (1 OR -1). AC1←STARTING JOB NUMBER.
;SKIP RETURN IF SUCCESS.

↑ESCQY:	PUSH P,TAC		;PRESERVE TAC
	PUSHJ P,ESCQX		;LOOK FROM AC1 TO END OF TABLE
	JRST TPOPJ1		;GOT ONE
	XORI AC1,JOBN		;START OVER AT OTHER END OF TABLE
	PUSHJ P,ESCQX		; AND LOOK THROUGH WHOLE TABLE
	JRST TPOPJ1		;GOT ONE.
	JRST TPOPJ		;NO JOB FOUND WITH SAME PN, NOT EVEN ORIGINAL JOB.

↑↑ESCQX:ADD AC1,AC3		;MOVE ON TO NEXT JOB
	CAIGE AC1,JOBN		;AT END OF TABLE YET?
	JUMPG AC1,.+2		; OR AT BEGINNING OF TABLE?
	JRST CPOPJ1		;YES TO ONE OF THESE
	HRRZ TAC,PRJPRG(AC1)	;GET PROGRAMMER NAME FOR THIS JOB
	CAIE TAC,(AC2)		;IS IT THE ONE WE ARE LOOKING FOR?
	JRST ESCQX		;NO
	MOVE TAC,JBTSTS(AC1)
	TLNN TAC,JNA
	JRST ESCQX
	POPJ P,			;DIRECT RETURN FOR SUCCESS
;ESCI ESCX ESCX2 ESCX1 ESC2X ESC2X1 REWHO ESC2X2 ESC2X3 ESC2X5

↑ESCI:	MOVSI AC3,INTTTI	;<ESC>I INTERRUPTS ON THE INTTTI BIT IN LEFT HALF
	LDB AC2,PJOBN
	TDNN AC3,JBTIEN(AC2)
	POPJ P,
	IORM AC3,JBTIRQ(AC2)
	SETOM INTREQ
	MOVEM AC1,INTDTM(AC2)	;Give him the arg as the datum of the interrupt
	POPJ P,

↑ESCX:	LDB AC3,PJOBN		;GET JOB NUMBER OF THIS GUY
	JUMPE AC3,CPOPJ		;IF YOU'RE NOT LOGGED IN, I CAN'T HELP YOU
	MOVSI TAC,NOXRST	;THIS IS THE BIT WE WILL SET OR CLEAR
	JUMPN AC1,ESCX2		;WAS IT PLAIN [ESC]X?
	ANDCAM TAC,JBTMSC(AC3)	;YES.  TURN OFF THE NO-UPDATE BIT
	POPJ P,			;BYE

ESCX2:	HRRZ AC2,AC1
	CAIN AC2,2
	JRST ESC2X		;ESC/BRK 2 X IS A DIFFERENT COMMAND!
	IORM TAC,JBTMSC(AC3)	;TURN ON NO-UPDATE FLAG
	TRNN AC1,-1		;WAS THERE AN ARGUMENT TO ESCAPE COMMAND?
	POPJ P,			;NO
	SETZB DSER,XTIME(AC3)
IFN FTMTRACT,<
	LSH AC3,1
	SETZM MTRXTIME(AC3)
	SETZM MTRXTIME+1(AC3)
	LSH AC3,-1
>;IFN FTMTRACT
	HRRZS DSKOPS(AC3)	;MAKE ALL DISK OPS "RECENT"
	JUMPL AC1,ESCX1		;WAS IT [ESC] OR [BRK]?
	SKIPGE DSER,JBTWAT(AC3)	;[ESC]1 X.  UPDATE JB2WAT
	ADD DSER,UPTIME		;MAKE WAIT TIME HONEST
	HRLS DSKOPS(AC3)	;ZERO INCREMENTAL COUNT OF DISK OPERATIONS
	MOVE TAC,TTIME(AC3)	;[ESC]1 X.  UPDATE XTIME
	MOVEM TAC,XTIME(AC3)	;[BRK]1 X.  CLEAR XTIME
IFN FTMTRACT,<
	LSH AC3,1
	DMOVE AC1,MTRTTIME(AC3)
	DMOVEM AC1,MTRXTIME(AC3)
	LSH AC3,-1
>;IFN FTMTRACT
ESCX1:	MOVEM DSER,JB2WAT(AC3)	;SAVE NEW VALUE OF OLD WAIT TIME
	POPJ P,

ESC2X:	JUMPE J,CPOPJ		;THIS IS MEANINGLESS FOR NON-DISPLAY
	SKIPN AC2,WHOTAB(J)	;GET NUMBER OF JOB ON WHOLINE
	MOVE AC2,AC3		;NONE, USE OWN JOB
	HRRE TAC,JBTLIN(AC2)	;SEE IF THIS JOB IS DETACHED
	JUMPL TAC,ESC2X1	;IF SO, ANYONE CAN DIDDLE HIS WHOLINE
	MOVE AC3,PRJPRG(AC3)
	XOR AC3,PRJPRG(AC2)
	TRNE AC3,-1		;CAN ONLY DIDDLE WHOLINE OF JOB WITH SAME PROGRAMMER
	POPJ P,
ESC2X1:	HRRZ AC3,AC2		;JOB NUMBER
	JUMPGE AC1,ESC2X2
	HLLZS JBTDDB(AC3)	;TERMINATE DISPLAY OF FILESTATUS
↑↑REWHO:SKIPE AC1,WHOTAB(J)	;DO WE HAVE A WHOLINE UP?
	JRST NXTWHO		;YES, REDRAW IT NOW, WITHOUT THE FILESTATUS
	POPJ P,

ESC2X2:	HRRZ TAC,JBTDDB(AC3)	;GET OUR CURRENT WHOLINE FILE DDB
	JUMPE TAC,ESC2X3	;NONE
	PUSHJ P,FIL2		;FIND THIS DDB IN DEVICE CHAIN
	MOVEI AC1,DSKDDB	;DIDN'T FIND IT (?), START AT FRONT OF LIST
	PUSHJ P,ESC2X5		;TRY TO FIND NEXT DDB
	JUMPN AC1,CPOPJ		;IF DIDN'T FIND ANOTHER, LOOK THRU WHOLE LIST ONE
ESC2X3:	MOVEI AC1,DSKDDB	;START AT FRONT OF LIST
ESC2X5:	PUSHJ P,NXTDSK		;GET NEXT DISK DDB
	POPJ P,			;NONE, NOTHING TO DISPLAY
	LDB TAC1,[POINT JOBNSZ,DEVJBN(AC1),JOBNPS] ;GET JOB NUMBER FROM DDB
	CAME TAC1,AC3
	JRST ESC2X5		;NOT OURS
	HRRM AC1,JBTDDB(AC3)
	MOVE AC1,AC3		;JOB NUMBER
	JRST NXTWHO		;FORCE OUT WHOLINE NOW
;FNTAB FNT1 FNT4 FNT3 FNT2 FNT5

FNTAB:	TLO J,NOTABB		;PREPARE TO FIND NEXT TAB IN LINE.
	MOVE AC1,LEHPOS(J)	;Get cursor's column position
FNT1:	ILDB TAC,TAC1		;LOOK AT NEXT CHR.
	JUMPE TAC,FNT1		;IGNORE NULLS
	CAIN TAC,EOLCHR		;ARE WE AT END OF LINE ?
	POPJ P,			;YUP. RETURN LEAVING `NO TAB' BIT SET.
	CAIE TAC,11		;A TAB ?
	AOJA AC1,FNT1		;NO. INCREMENT HORIZONTAL POSITION FOR NEXT TAB
	MOVE AC2,TAC1		; SEE IF THIS TAB IS REALLY A LONG LINE CRLF
	ILDB AC2,AC2		; PICK UP CHARACTER PAST TAB
	CAIN AC2," "		; IS IT A SPACE?
	JRST FNT3		; YES, MUST BE REAL TAB
FNT4:	ILDB TAC,TAC1		; NO, MUST BE LONG LINE CRLF. READ PAST IT.
	CAIE TAC,11		; IS THIS A TAB?
	JRST FNT4		; NO, READ SOME MORE
	JRST FNT1		; YES, GET NEXT CHARACTER PAST CRLF

FNT3:	MOVEI AC2,0		;COUNT NO. OF SPACES IN TAB.
	MOVEM AC1,NTABHP(J)	;STORE HORIZONTAL POSITION OF THE TAB
	TLC J,TABB!NOTABB	;SET BITS PROPERLY.
FNT2:	ILDB TAC,TAC1
	JUMPE TAC,.-1		; SKIP NULLS
	CAIE TAC," "		;ARE WE OUT OF SPACES YET ?
	JRST FNT5
	MOVEM TAC1,NTABPT(J)	;STORE PTR. TO LAST SPACE IN TAB.
	AOJA AC2,FNT2		;NO. KEEP COUNTING.

FNT5:	CAIE TAC,11		; IS THIS REALLY THE TERMINATING TAB?
	JRST FNT2		; NO, GO BACK FOR MORE
	MOVEM AC2,NTABCT(J)	;STORE SIZE OF TAB.
	POPJ P,
;MOVEIT MVFOR MVBAK MVA MVA1 MVA2

;;MOVEIT MOVES THE PTR. FORWARD OR BACKWARD BY THE NO. OF PLACES
;; IN AC1, AND DELETES CHARS. PASSED OVER IF CHR=0.

MOVEIT:	MOVE TAC1,LEPNT1(J)	;GET CURRENT POINTER.
	POP P,DSER		;GET PTR. TO ARGUMENT.
	SETZB AC2,AC3
	MOVEM AC1,1(P)		;REMEMBER COUNT.
	SKIPN CHR		; ARE WE DELETING?
	TLO J,NOBRBT		; YES, REDO THE LONG-LINE CRLF WHEN DONE
	TLZ J,XTABBT		; CLEAR TAB BIT
	JRST @(DSER)		;GO TO EITHER MVFOR OR MVBAK.

MVFOR:	ILDB TAC,TAC1		;LOOK AT NEXT CHR.
	JUMPE TAC,.-1		;IGNORE NULLS.
	JUMPN CHR,MVA		;DON'T DELETE UNLESS CHR =0.
	DPB CHR,TAC1		;DELETE IT.
	JRST MVA
	
MVBAK:	LDB TAC,TAC1		;LOOK AT CURENT CHR.
	JUMPN CHR,.+2		;DELETE IT IF APPROPRIATE,
	DPB CHR,TAC1
	ADD TAC1,[XWD 070000,0]	;DECREMENT POINTER.
	JUMPG TAC1,.+2
	SUB TAC1,[XWD 430000,1]
	JUMPE TAC,MVBAK		;IF CURRENT CHR. WAS NULL,GET ANOTHER.
MVA:	CAIN TAC,11		;HAVE WE JUST ENCOUNTERED A TAB ?
	ADDI AC3,1		;YES.
	TRNN AC3,1		;ARE WE INSIDE A TAB ?
	JRST MVA1		; NO
	CAIN TAC,11		; YES, IS THIS A REAL TAB OR A LONG LINE CRLF?
	AOJA AC2,@(DSER)
	CAIN TAC," "
	JRST MVA2		; MUST BE A REAL TAB, SET THE BIT THAT SAYS SO
	SKIPN CHR		; IF WE ARE DELETING, WE MUST REPOSITION THE CRLF
	TLO J,NOBRBT		; DO SO BY PRETENDING THERE HAVEN'T BEEN ANY
	CAIE TAC,15		; BUMP COUNT ONE AT THE CR TO MAKE THE ENTIRE CRLF INVISIBLE
	JRST @(DSER)		; OTHERWISE, JUST LOOP AROUND
	TLNE J,XTABBT		; IF THIS IS A LONG LINE CRLF ONLY, THEN
	JRST @(DSER)
	SUBI AC1,1		; CORRECT COUNT
	AOJA AC2,@(DSER)

MVA1:	TLZ J,XTABBT
	AOJL AC1,@(DSER)	; COUNT DOWN RPT. CNT AND LOOP.
	JUMPE AC3,.+2		;ALL DONE. DID WE PASS ANY TABS ?
	TLZ J,TABB!NOTABB	;YES. WE NO LONGER KNOW WHERE NEXT ONE IS.
	SUB AC2,1(P)		;ADD NO. OF CHRS. PASSED TO NO. OF SPACES IN TABS PASSED.
	SUBB AC2,AC3		;SUB. 2⊗NO. OF TABS. THIS (MIRABILE DICTU!) GIVES NO. OF COLUMNS MOVED.
	JRST 1(DSER)

MVA2:	TLO J,XTABBT
	AOJA AC2,@(DSER)
;INIT2 INIT4 INIT4B INIT4A INIT4C CRKILL

INIT2:	MOVE TAC,ACTMOD(DDB)	;GET SPECIAL BITS
	TLNN IOS,TPMON		;CAN'T SUPPRESS CTRL CR IN MONITOR MODE
	TRNN TAC,SUPCCR		;SUPPRESS CTRL CR?
	CAIE CHR,1B28!15	;HAS LOSER TYPED CONTROL-CR ?
	JRST INITIT		;NO. RESET EVERYTHING FOR NEW LINE.
	SKIPN LEPNT1(J)		;HAVE WE INITIALIZED AT LEAST ONCE?
	JRST INITIT		;NO, DO SO NOW.
	PUSHJ P,QLETXF		;QUEUE UP A TRANSFER IF DD/DM, FLUSHING QUEUE FIRST
INIT4:	HRLI J,400000!REEDBT!NOCRBT
	SETZM LCH(J)
;	JUMPGE UCHN,INIT4B
;	TLNE DAT,LERSEE
;	TLO J,SHLDRB		;POOLE MODE FLUSHED
				;LET LOSER EDIT PREVIOUS LINE SOME MORE.
INIT4B:	MOVEI UUO,2		;PREPARE TO REMOVE THE CR LF FROM END OF LINE.
INIT4A:	LDB TAC,LEPNT1(J)	;(WE DON'T WANT TO LET THE LOSER EDIT THEM. )
	CAIE TAC,12		;IF IT IS A LF ...
	CAIN TAC,15		;... OR A CR ...
	JRST INIT4C		;FLUSH IT
	CAIN TAC,177		;IF A RUBOUT,
INIT4C:	PUSHJ P,CRKILL		;... THEN WE THROW IT OUT.
	SOJG UUO,INIT4A		;ALLOW FOR BOTH A LF AND A CR.
	DPB UUO,PLASTC
	PUSHJ P,LEPACK		;FLUSH FROM END OF BUFFER UNTIL BUFFER NOT FULL
	TLZ J,NOTABB!ACTNOW	;BS ROUTINE WILL HAVE SET NOTABB, GCOLL SET ACTNOW
	SKIPN FCPOS(J)		;IS LINE EMPTY?
	TLO J,EOLBT		;YES, TELL SOMEONE PLEASE!!!!!
	SUB P,[1,,1]		;POP UP A LEVEL -- AVOID RETURNING TO NOINIT
	PUSHJ P,INIT3		;RESET THE POINTER POSITION TO BEGINNING OF LINE
	JRST LECX		;MAY NEED TO CALL MAKECR IF LEPACK DELETED ANYTHING

;THIS IS A ROUTINE FOR DELETING THE CRLF FROM THE END OF A LINE
;THAT WE GOT FROM PTLOAD OR <CONTROL>CR.

CRKILL:	MOVNI AC1,1		;TELL BACKSPACE ROUTINE TO DELETE ONE CHR.
	ADDM AC1,FCPOS(J)	;DECREMENT THE TOTAL NUMBER OF CHARACTERS IN THE BUFFER
	TLZ J,NOCRBT
	SETZ CHR,		;FLAG DELETING OPERATION TO MOVEIT
	PUSHJ P,MOVEIT		;BACK THE POINTER UP, DELETING THE CRLF AS IT GOES
	 MVBAK			;Arg to subroutine
	MOVEM TAC1,LEPNT1(J)	;STORE THE UPDATED POINTER
	POPJ P,
;INITIT INIT3 INIT1 LEINIT

; THIS IS THE INITIALIZE ROUTINE. HERE WE INITIALIZE ALL THE LINE
; EDITOR VARIABLES

INITIT:	PUSHJ P,LEINIT		;INIT THE BUFFER ITSELF
	TLZ J,¬REEDBT		;REMEMBER IF IS RE-EDITED LINE (MAYBE DID A CLEAR)
	TLO J,EOLBT+400000
	SETZM LCH(J)
	MOVEI TAC,LEBUF(J)	;GET START OF LINE BUFFER.
	HRRZM TAC,LELWD(J)	;INIT. PTR. TO RETURN JMP.
INIT3:	SETZM LEHPOS(J)		;HORIZONTAL POSITION.
	SETZM NUMARG(J)		; CLEAR THE REPEAT ARGUEMENT
	HLLM J,LETAB(DAT)	; STORE THE FLAG BITS BACK INTO THE LINE EDITOR TABLE
	SETZM CCPOS(J)		;CHARS. FROM START OF LINE.
	MOVE TAC,[LVW (12,-4,I,R,2,2)]
	MOVEM TAC,LEPPV(J)	;INITIAL POS. OF CURSOR.
	HRRZS LELMARG(J)	;RESET LEFT MARGIN.
INIT1:	HRLI TAC,440700		;MAKE INITIAL BYTE PTR.
	HRRI TAC,LEBUF(J)
	MOVEM TAC,LEPNT1(J)
	POPJ P,

↑LEINIT:MOVEI TAC,EOLCHR*2+1	;GET DPY CHR WORD WITH LINE TERMINATING CHR IN IT
	MOVEM TAC,LEBUF(J)	;PLACE IN FIRST WORD OF BUFFER.
	MOVEI TAC,LEB(J)	; PUT RETURN JUMP IN SECOND WORD
	HRLI TAC,DISJMP
	MOVSM TAC,LEBUF+1(J)
	SETZM FCPOS(J)		;NO. OF CHARS. IN LINE.
	POPJ P,
;LACTV1 LACTIV PTLLX ACTNON ACTIV1 ACTNH0

;ENTER AT LACTIV WITH NUMBER OF CHARS TO ACTIVATE IN TAC
LACTV1:	MOVEI TAC,1		;ONE CHARACTER PLEASE
↑LACTIV:TDZA UCHN,UCHN		;NO SPURIOUS CTRL BITS PLEASE.
PTLLX:	PUSHJ P,STLNAC		;SETUP LINE!
	TLNN LINE,DISLIN!DDDLIN!DMLIN ;IF A DPY, XFER EDITOR BUFFER TO INPUT BUFFER NOW.
	POPJ P,			; IF NOT A DPY, RETURN NOW
	MOVE DAT,LINE
	SKIPGE J,LETAB(DAT)
	SKIPG FCPOS(J)
	POPJ P,			;NOTHING IN EDITOR BUFFER. FERGIT IT.
	JRST ACTNH0

;HERE IF WE FOUND NOTHING TO ACTIVATE AFTER ALL
ACTNON:	TLC J,400000!WTFLAG	;READY FLAG ON, WAIT FLAG OFF
	HLLM J,LETAB(DAT)
	POPJ P,

ACTIV1: JUMPGE J,CPOPJ		;POOLE AND HIS RECURSIVE CALLS ON ACTIV1 !
	PUSHJ P,NOHOLD		;MAKE SURE WE ARE NOT HOLDING
	MOVE TAC,ACTMOD(DDB)	;GET SPECIAL BITS
	TLNN IOS,TPMON		;NO EMODE IN MONITOR MODE
	TRNN TAC,EMODE		;IN EMODE, ACTIVATE EVERYTHING
	SKIPA TAC,CCPOS(J)	;ONLY ACTIVATE UP TO CURSOR NORMALLY
	MOVE TAC,FCPOS(J)	;MAKE COPY OF NO. OF CHRS. IN BUFFER.
	TLZE J,ACTNOW		;ACTIVATE WHOLE BUFFER IF OUT OF BUFFER SPACE
	MOVE TAC,FCPOS(J)	;NUMBER OF CHARS TO ACTIVATE
	TLZN J,REEDBT		;IS THIS A RE-EDIT ?
	JRST ACTNH0
	DPB UCHN,[POINT 2,CHR,28]
	DPB CHR,[POINT 9,GWORD(J),35]
	MOVE AC1,FCPOS(J)	;Let INWAITers know how much was really in line
	DPB AC1,PLASTC		;YES. REMEMBER LINE LENGTH.
;;;	MOVEI CHR,400
;;;	TLZE J,SHLDRB	;IS loser looking over our shoulder ?
;;;	PUSHJ P,LSRSEE	;Yes. Flag end of edit chrs.
ACTNH0:	TLC J,400000!WTFLAG	;READY FLAG OFF, WAIT FLAG ON.
	AOJG UCHN,.+2		;IS PTYSER PRE-LOADING US WITH A LINE TO EDIT ?	
	PUSHJ P,INIT4		;YOU BETCHUM, R.R.  DON'T ACTIVATE GUY.
	HLLM J,LETAB(DAT)	;MAKE SURE WTFLAG IS ON BEFORE WE DIDDLE THINGS
	CAMLE TAC,FCPOS(J)	;CAN'T ACTIVATE MORE CHARS THAN THERE ARE
	MOVE TAC,FCPOS(J)
	JUMPE TAC,ACTNON	;IF NOTHING IN LINE EDITOR, DON'T ACTIVATE
	MOVEM TAC,NTABCT(J)	;SAVE NUMBER OF CHARACTERS TO ACTIVATE
	CAME TAC,FCPOS(J)	;ARE WE GONNA ACTIVATE EVERYTHING?
	TLOA UCHN,400000	;FLAG NOT ACTIVATING EVERYTHING
	TLZ J,NOCRBT		;Remember that we activated line, didn't CLEAR it
	MOVEM UCHN,NTABPT(J)	;SAVE CTRL BITS OF ACTIVATION CHR.
	TLZ J,TABB!NOTFR!NOTEXT	;MARK NTABPT, NTABCT INVALID.  FORCE OUTPUT.
	MOVE TAC,LEPNT1(J)	;SAVE BYTE POINTER TO CURRENT CHAR SO WE
	MOVEM TAC,SVPNT1(J)	; CAN PRESERVE USER'S CURSOR POSITION
	PUSHJ P,INIT1		;RESET LEPNT1.
	HLLM J,LETAB(DAT)	; STORE NEW STATUS.
;PATCH BY RPH TO TRANSFER AS MANY CHARS AS WILL FIT IN
;TTY BUFFER NOW!!!!!! NOT LATER AT CLOCK LEVEL
	PUSH P,DAT		;SAVE LINE NUMBER AND BITS
	PUSHJ P,LEFLUS		;Flush DM line editor queue since activating
	PUSHJ P,ACTIV3		;CALL HIM ONCE
	POP P,DAT		;GET BACK LINE NUMBER
	MOVE J,LETAB(DAT)	;AND BITS
	POPJ P,			;AND RETURN TO WHO EVER
;ACTIV3 ACTIV9 ACTIVL ACTIV6 ACTIVQ ACTIVP ACTIVR ACTIVS ACTIVZ ACTIVY ACTIV4 ACTIV5

;SET UP EVERYTHING AND GO BACK INTO LOOP.  MOVE LINED BUFFER TO TTY BUFFER
↑ACTIV3:HRRZ LINE,DAT
	HLL LINE,LINTAB(LINE)	;GET DISPLAY-TYPE BIT
	MOVE J,LETAB(LINE)
	TLNE LINE,DISLIN!DDDLIN!DMLIN	;GOTTA BE A DISPLAY
	TLNN J,WTFLAG		;SKIP IF TRANSFER IN PROGRESS
	POPJ P,
	SKIPN DDB,TTYTAB(DAT)
	JRST ACTIV7		;SOMEBODY FLUSHED OUR DDB.  QUIT NOW.
ACTIV9:	MOVE IOS,DEVIOS(DDB)
	MOVE J,LETAB(LINE)
	MOVEI UCHN,TTIBUF(DDB)	;GET POINTER FOR PUTCHI.
	HRRZ DDB,J		;PICK UP ADDRESS OF DPY PROGRAM HEADER
	MOVE TAC1,CURPP(J)	;POINTER TO PP BLOCK
	HLL DDB,PPDPY(TAC1)	;GET DISPLAY-TYPE BIT FOR DPYTYO
	SKIPG NTABCT(J)
	JRST ACTIVR		;HERE IF E MODE 400 OVERFLOWED TTY BUFFER
ACTIVL:	MOVEM UCHN,DAT		;GIVE PUTCHI A PTR. TO INPUT BUFFER.
	MOVEI TAC1,LEPNT1(J)	;TELL GETEM TO USE LEPNT1.
	PUSH P,LEPNT1(J)	;SAVE BYTE POINTER BEFORE CHAR
	PUSHJ P,GETEM		;GET NEXT CHR. FROM BUFFER.
	PUSHJ P,PUTCHI		;PLACE CHAR. IN TTY INPUT BUFFER.
	 JRST ACTIV2		;INPUT BUFFER FULL. WAIT A WHILE.
	SOSE CCPOS(J)		;IS THIS THE ACTIVATION CHAR. ?
	JRST ACTIV6		;NO
	HRRZ TAC,NTABPT(J)	;YES. DOES IT HAVE CTRL. BITS ?
	SOJLE TAC,ACTIV6	;NO
	DPB TAC,[POINT 2,CHR,28];YES. PUT CTRL. BITS IN INPUT BUFFER.
	DPB CHR,PUTR(DAT)
	MOVEI CHR,"α"		;ECHO CTRL. BITS, IF ANY.
	TRNE TAC,CBIT1
	PUSHJ P,ECHOCB
	MOVEI CHR,"β"	
	TRNE TAC,CBIT2
	PUSHJ P,ECHOCB
ACTIV6:	LDB CHR,LEPNT1(J)	;GET BACK DPY VERSION OF CHAR. CODE.
	PUSHJ P,ECHO		;ECHO IT ON PAGE PRINTER.
	TLNN DDB,DDDLIN		;DATA DISC?
	JRST ACTIVQ		;NO
	LDB CHR,LEPNT1(J)	;GET LAST CHR PUT OUT
	CAIN CHR,177		;IS IT A BS
	PUSHJ P,ECHO		;YES, ECHO TWICE FOR DD
ACTIVQ:	POP P,CHR		;GET BACK BYTE POINTER TO PREV CHAR
	SKIPL NTABPT(J)		;ARE WE NOT ACTIVATING EVERYTHING?
	JRST ACTIVP		;NO, WE ARE ACTIVATING EVERYTHING
	MOVEM CHR,LEPNT1(J)	;RESTORE BYTE POINTER TO PREVIOUS CHAR
	MOVNI AC1,1		; SO WE CAN DELETE CURRENT ONE
	ADDM AC1,FCPOS(J)	;DECREMENT TOTAL CHAR IN LINE EDITOR
	MOVEI CHR,0		;DELETE -(AC1) CHAR
	PUSHJ P,MOVEIT		;DELETE FORWARD ONE CHAR FROM LINE EDITOR
	 MVFOR			;ARG TO MOVEIT
	MOVNS DSER,AC2		;- NUMBER OF COLUMNS MOVED
	IMUL AC2,XDEL2		;CALC. AMOUNT TO MOVE CURSOR.
	LSH AC2,1		;THIS IS TO HANDLE OVERFLOW.
	ADDM AC2,LEPPV(J)	;UPDATE THE POSITION VECTOR.
	ADDM DSER,LEHPOS(J)	;UPDATE HORIZONTAL POS. CNT.
ACTIVP:	SOSLE NTABCT(J)		;ALL CHRS. XFERED ?
	JRST ACTIVL		;NO
	MOVEI TAC,EMODE		;ARE WE IN E MODE?
	MOVEI DDB,-TTIBUF(UCHN)	;WHY DON'T WE HAVE DDB SET UP GRUMBLE GRUMBLE
	TLNN IOS,TPMON		;NO EMODE IN MONITOR MODE
	TDNN TAC,ACTMOD(DDB)
	JRST ACTIVS		;NOT E MODE
ACTIVR:	MOVEM UCHN,DAT
	MOVEI CHR,400		;YES, FLAG END OF ACTIVATED TEXT
	PUSHJ P,PUTCHI		;PUT 400 INTO INPUT BUFFER
	 JRST ACTI21		;INPUT BUFFER FULL, GET BACK HERE BY SEEING NTABCT≤0
;HERE WHEN THE LINE EDITOR BUFFER IS EMPTY.  CLEAN UP AND LEAVE.
ACTIVS:	SKIPL NTABPT(J)		;DID WE ACTIVATE EVERYTHING?
	JRST ACTIVZ		;YES
	MOVE TAC,SVPNT1(J)	;NO
	MOVEM TAC,LEPNT1(J)	;RESTORE NORMAL POINTER FOR REMAINDER OF LINE
	TLC J,400000!WTFLAG	;READY FLAG BACK ON, WAIT FLAG OFF
	SKIPL CCPOS(J)		;DID WE ACTIVATE CHAR OVER CURSOR?
	JRST ACTIVY		;NO
	SETZM CCPOS(J)		;YES, RESET NUMBER OF CHARS TO LEFT OF CURSOR
	MOVE TAC,[LVW (12,-4,I,R,2,2)]
	MOVEM TAC,LEPPV(J)	;INITIAL POS. OF CURSOR.
	HRRZS LELMARG(J)	;RESET LEFT MARGIN.
	SETZM LEHPOS(J)		;RESET HORIZ POS OF CURSOR IN COLUMNS
	TLNE J,INSBT
	PUSHJ P,ACTIVX		;STILL IN INSERT MODE, FIX THE CURSOR POSITION
	JRST ACTIVY

ACTIVZ:	MOVEI DDB,LEB(J)	; YES, MAKE EDITOR BUFFER INVISIBLE BY PUTTING
	HRLI DDB,DISJMP		; A RETURN JUMP ON TOP OF THE POSITION VECTOR
	MOVSM DDB,LEPPV(J)
	HRLI J,0		;RESET STATUS BITS.
ACTIVY:	TLZ IOS,SYNC!DDTM	;DONT SCREW UP THE COUNT
ACTIV4:	MOVEI DDB,-TTIBUF(UCHN)	;RECOVER DDB.
	TLNE J,WTFLAG		;HAVE WE FINISHED ACTIVATING THE LINE EDITOR?
	JRST ACTIV5		;NO
	PUSH P,J		;SAVE DPY HEADER
	PUSHJ P,PTICHK		;ACTIVATE JOB WAITING TO STUFF TEXT IN LINE EDITOR
	POP P,J			;PTICHK ALSO CLOBBERS TAC AND TAC1, BUT NO MATTER
ACTIV5:	PUSHJ P,STLNAC		;SET UP LINE (TAC1).
	HLLM J,LETAB(LINE)	;RESET STATUS. 
	PUSH P,TISYNC(DDB)	;REMEMBER CURRENT ACTIVATION COUNT!
	PUSHJ P,SYNCHK		;UPDATE TISYNC
	POP P,TAC		;GET BACK ORIGINAL COUNT
	CAMGE TAC,TISYNC(DDB)	;DID SYNCHK ACTIVATE SOME MORE CHARS?
	JRST RECIN3		;YES, WAKE COMMAND DECODER!
	JRST RECIN4
;ACTIV2 ACTI21 ACTIV7 ACTIV8 ACTI10

ACTIV2:	POP P,LEPNT1(J)		;RESTORE BYTE POINTER TO CHAR BEFORE LOSER
ACTI21:	TLO IOS,SYNC!DDTM	;FORCE ACTIVATION
	PUSHJ P,ACTIV4		;GO ACTIVATE JOB.
	SKIPL TTYTAB(LINE)	;SKIP IF COMMAND ALREADY WAITING
	PUSHJ P,COMSET		;NO, SET HIM
	MOVE DAT,LINE
	POPJ P,

; WE GET HERE IF THE DDB HAS BEEN EATEN FROM UNDERNEATH US
; WE TRY TO GET HIM A NEW DDB.

ACTIV7:	OFFSCN			;TURN OFF SCANNER CHANNEL
	SKIPE DDB,TTYTAB(DAT)	;SEE IF IT IS REALLY GONE?
	JRST ACTIV8		;NOT REALLY, GO TO IT
	PUSHJ P,DDBSRC		;GET HIM A DDB
	 JRST ACTI10		;NONE AVAILABLE, REPLANT CLOCK REQUEST AND WAIT
ACTIV8:	ONSCN			;TURN ON SCANNER CHANNEL
	JRST ACTIV9

ACTI10:	ONSCN			;TURN ON SCANNER CHANNEL
	JRST DPYTIM
;ECHOCB ECHO SHIFT SHIFTR SHIFTL SHIFT2

ECHOCB:	TRNE IOS,NOECHB!NOECHO	;IS USER SUPPRESSING ECHO OF CTRL BITS OR ALL CHARS?
	TLNE IOS,TPMON		;YES, MONITOR GETS THEM ANYWAY
	JRST DPYTYO		;ECHO BIT
	POPJ P,

ECHO:	TLNE IOS,TPMON		; ALWAYS ECHO IN MONITOR MODE
	JRST DPYTYO
	TRNE IOS,NOECHO		;IS USER SUPPRESSING ALL ECHOING ?
	POPJ P,
	MOVE AC1,LCH(J)
	MOVEM CHR,LCH(J)
	CAIN CHR,12
	CAIE AC1,15
	JRST DPYTYO
	HRRZ AC1,PRGNUM(J)	; PICK UP TTY NUMBER
	MOVE AC1,LINTAB(AC1)	; FILL IN LINE CHARACTERISTICS
	TLNN AC1,PTYLIN		; IF THIS IS A PTY, THEN XON IS HANDLED IN PUTCHR
	TLNN AC1,XON		; LET THE LOSER TURN OFF ECHO OF LF AFTER CR
	JRST DPYTYO
	POPJ P,

SHIFT:	JUMPG DSER,SHIFTL	;OVER LEFT MARGIN ?
SHIFTR:	SKIPA AC2,.+1		;SHIFT LINE RIGHT.
SHIFTL:	MOVNI AC2,30		;SHIFT LINE LEFT.
	SKIPN III(J)		; ARE WE A DD OR DM DISPLAY?
	POPJ P,			;YES, DON'T SHIFT LINE 'CAUSE IT SCREWS UP DPHPOS
	HRRES DSER,AC2
	IMUL AC2,XDEL
	ADDM AC2,LELMARG(J)	;MOVE WHOLE LINE OVER.
SHIFT2:	ADDM AC2,LEPPV(J)	;UPDATE THE POSITION VECTOR.
	ADDB DSER,LEHPOS(J)	;UPDATE HORIZONTAL POS. CNT.
	CAIG DSER,=72		;PAST RIGHT HAND MARGIN ?
	JUMPGE DSER,CPOPJ	;OR MAYBE PAST LEFT ?
	JRST SHIFT		;LOOP BACK TO SHIFT SOME MORE
;PTLOAD PTL7W9 PTLLED EPTL1 EPTL2 PTLL0 PTLL4 PTLL3 PTLL09 PTLL2 PTLLX1 PTLLX9 RSTECH PTLLX0

COMMENT ⊗
PTLOAD: UUO IS HERE ⊗

;LOAD LINE EDITOR WITH 7-BIT STRING, THEN WRITE A NINE BIT STRING
↑PTL7W9:TDZA CHR,CHR		;FLAG PTL7W9 UUO
↑PTLLED:SETO CHR,		;FLAG A PLAIN PTLOAD UUO
	TLNN LINE,DISLIN!DDDLIN!DMLIN	;IF A DPY, PRELOAD THE LINE EDITOR
	POPJ P,
	SETZM PTLBUF
	MOVE TAC,[PTLBUF,,PTLBUF+1]
	BLT TAC,PTLBUF+PTLBUL-1	;CLEAR THE BUFFER BUFFER
	MOVE TAC,[POINT 9,PTLBUF]
	MOVEM TAC,PTLPTR	;USED TO STORE USER INPUT
	MOVEM TAC,PTLTKR
	PUSH P,CHR		;SAVE FLAG INDICATING UUO
	JUMPN CHR,EPTL2		;JUMP IF PLAIN PTLOAD
	XCTR XR,[MOVE AC1,1(UUO)] ;GET PTR TO 9-BIT STRING OF "TYPE-AHEAD"
	TLNN AC1,-1		;BYTE POINTER YET?
	HRLI AC1,441100		;NOW IT IS
	TLZ AC1,77		;Clear indirect/index/unused bits in byte ptr
EPTL1:	XCTR XLB,[ILDB CHR,AC1]	;GET 9-BIT CHAR
	JUMPE CHR,EPTL2		;END WITH NULL
	PUSHJ P,PTLPUT		;SAVE CHAR FOR LATER
	JRST EPTL1

EPTL2:	OFFSCN			;TURN OFF SCANNER CHANNEL
	PUSH P,DEVIOS(DDB)	;SAVE OLD STATE OF NOECHO BIT
	MOVEI IOS,NOECHO
	IORB IOS,DEVIOS(DDB)	;PREVENT ECHO OF STUFF WE GRAB FROM LINE EDITOR
PTLL0:	PUSHJ P,LACTV1		;Get one char from line editor
	MOVEI DAT,TTIBUF(DDB)
	PUSHJ P,GETCHY		;READ A CHAR
	JUMPE CHR,PTLL09	;NONE TO READ
	CAIN CHR,15		;IS IT A CR?
	JRST PTLL3		;YUP
PTLL4:	CAIE CHR,400		;DON'T BE FOOLED IF E MODE CONSES THIS UP
	PUSHJ P,PTLPUT		;PUT IN OUR BUFFER
	JRST PTLL0

PTLL3:	PUSHJ P,LACTV1		;Get one char from line editor
	MOVEI DAT,TTIBUF(DDB)
	PUSHJ P,GETCHY		;get input char, which better be a LF
	XORI CHR,15≠12		;CONVERT LF INTO A CR, WITH CONTROL BITS IN PLACE
	JRST PTLL4		;NOW STORE THE CR

PTLL09:	XCTR XR,[MOVE UUO,(UUO)];GET GUY'S PTR.
	TLNN UUO,-1		;IS IT ALREADY (PRESUMABLY) A BYTE PTR. ?
	HRLI UUO,440700		;NO. MAKE IT ONE.
	TLZ UUO,77		;NO INDEXING ALLOWED
	MOVE CHR,UUO		;MAKE A COPY OF BPT
	XCTR XLB,[ILDB CHR,CHR]	;SNEAK FIRST CHAR
	CAIE CHR,15		;IS THIS PTLOAD OF AN EMPTY LINE?
	TDZA AC1,AC1		;NO, RESTORE ECHO STATE NOW
	MOVE AC1,PTLPTR		;Byte pointer to stuff already echoed
	ANDB AC1,-1(P)		;Save byte pointer if plain PTLOAD
	JUMPN AC1,.+2
	JSP AC2,RSTECH		;PTL7W9 UUO, restore former echo state now
	MOVSI IOS,PTLIP
	IORB IOS,DEVIOS(DDB)	;NO USER TYPEIN CAN INTERFERE WITH US NOW
	ONSCN			;WE'RE SUPPOSED TO BE SAFE NOW WITH PTLIP
PTLL2:	XCTR XLB,[ILDB CHR,UUO]	;GET CHR. FROM LOSER.
	MOVSI UCHN,-1		;FLAG TO KBDED SAYING IT'S US.
	JUMPE CHR,PTLLX0	;IF NULL, QUIT AND RESET EDITOR.
	PUSHJ P,STLNAC
	PUSHJ P,KBDED		;This never actually activates
	TRNN UCHN,1		;DID KBDED SEE AN ACTIVATION CHR. ?
	JRST PTLL2		;NO. 
PTLLX1:	OFFSCN
	ILDB CHR,PTLTKR
	JUMPE CHR,PTLLX9	;NO BUFFERED CHARS LEFT TO TRANSFER
	LDB UCHN,[POINT 2,CHR,28]
	CAIN CHR,600
	MOVEI UCHN,0		;NO BUCKY BITS WANTED IN UCHN FOR CALL
	MOVEI DSER,(CHR)
	ANDI DSER,177		;MORE KBDED SETUP
	PUSHJ P,STLNAC
	PUSHJ P,KBDED		;This may activate line, so scanner must be off
	ONSCN
	SKIPE AC1,-1(P)
	CAME AC1,PTLTKR		;ARE WE UP TO END OF ECHOED TYPEAHEAD?
	JRST PTLLX1		;NO
	JSP AC2,RSTECH		;YES, RESTORE ECHO TO FORMER STATE
	SETZM -1(P)		;DON'T GET HERE AGAIN
	JRST PTLLX1

PTLLX9:	SKIPE -1(P)
	JSP AC2,RSTECH		;Restore old state of NOECHO bit
	SUB P,[2,,2]		;Flush saved IOS and flag saying which UUO
	MOVSI IOS,PTLIP		;TURN OFF PTLOAD MODE
	ANDCAB IOS,DEVIOS(DDB)
	JRST SCNONJ

RSTECH:	MOVE AC1,(P)		;GET SAVED FORMER STATE OF NOECHO BIT
	TRNE AC1,NOECHO		;IF IT WAS ON, LEAVE IT ON
	JRST (AC2)
	MOVEI IOS,NOECHO
	ANDCAB IOS,DEVIOS(DDB)	;IT WAS OFF, TURN IT BACK OFF
	JRST (AC2)

PTLLX0:	PUSHJ P,PTLLX		;SET CURSOR TO BEGINNING OF LINE
	JRST PTLLX1
;QLETX2 QLETXF QLETXT QLECUR LEFLUS

; HERE IS WHERE WE QUEUE UP LINE EDITOR TRANSFERS

QLETX2:	MOVE AC1,PRGNUM(J)	;Here only from main LINED outer routine KBDX1
	TLNE AC1,DMLIN
	TLNE J,DMDAMN		;Extra hard case here
	JRST QLETXF		;Not DM or too hard for now
	TLZE J,DMHARD		;Is this a hard DM xfer?
	SKIPN NCRS(J)		;Yes, but are there multiple lines in LE?
	JRST QLECUR		;No, trivial
QLETXF:	PUSHJ P,LEFLUS		;Flush DM line editor queue
↑↑QLETXT:			;LERELE enters here to redraw DD line editor
	SETOM LETXC(J)		; NOTE THAT TEXT HAS CHANGED and must be redrawn
QLECUR:	SKIPE III(J)		; IF III, THIS IS IRRELEVANT
	POPJ P,
	SETO AC2,		; TEST THE FLAG
	EXCH AC2,LECLK(J)	; IS THERE A CLOCK REQUEST ALREADY IN?
	JUMPL AC2,CPOPJ		; IF SO, HE WILL GET IT.
	HRR AC1,J		; IF NOT, MAKE UP ONE WITH THE DPY HEADER ADDRESS IN IT
	HRLI AC1,DPLED		; AND USE THE LINE EDITOR ROUTINE
	JRST AC1CLK		;PLANT CLOCK REQUEST FROM AC1

LEFLUS:	MOVE AC1,PRGNUM(J)	;Get display bit or DD channel in LH
	TLNE AC1,DMLIN		;We only want to flush DM line editor queue
	TLNE IOS,PTLIP		;But not if in middle of PTLOAD
	POPJ P,
	MOVEI AC2,DMLEPT(J)	;Address of DM line editor queue to flush
	JRST DMFLUS		;Flush DM's LE queue since we need to redraw line
;MAKECR LEFIX MAKEC1

; THIS IS A ROUTINE THAT GOES THROUGH THE LINE AND SETS UP EXTRA CRLFS TO BREAK
; LONG LINES.

MAKECR:	TLZ J,TABB!NOTABBT	; NEXT TAB IS UNKNOWN NOW
	TLNE J,400000		; IS IT REALLY THERE?
	SKIPE III(J)
	POPJ P,			; NOT THERE OR III
↑↑LEFIX:SETZ AC3,
	MOVE AC2,CURPP(J)	; PICK UP PAGE PRINTER CONTROL BLOCK ADDRESS
	MOVE AC1,PPHPOS(J)
	SUB AC1,LNLNGT(AC2)	;ROOM LEFT TO END OF LINE
	HRLI TAC,440700		; PICK UP BYTE POINTER TO BEGINNING OF BUFFER
	HRRI TAC,LEBUF(J)
	SETZM NCRS(J)		; INITIALIZE THE TRANSFER LENGTH COUNTER
MAKEC1:	ILDB CHR,TAC		; PICK UP CHARACTER
	JUMPE CHR,.-1		; SKIP NULLS
	CAIN CHR,EOLCHR		; IF END OF BUFFER,
	JRST MAKEC6		; LEAVE
	CAIN CHR,11		; IS THIS A TAB?
	JRST MAKEC2		; YES, IT IS, GO PROCESS IT
	AOJL AC1,MAKEC7		; NORMAL CHARACTER, BUMP COLUMN COUNT
;MAKE12 MAKE23 MAKE22 MAKE20 MAKE21 MAKE24 MAKEC8 MAKEC9 MAKEC7 MAKE10

; WE GET HERE IF THE LINE IS LONG AND MUST BE BROKEN UP.

MAKE12:	MOVE AC1,TAC		; PICK UP BYTE POINTER
MAKE23:	ILDB CHR,AC1		; LOOK AHEAD SOME
	JUMPE CHR,.-1
	CAIE CHR,11		; MAYBE THIS IS JUST THE LONG-LINE CRLF?
	JRST MAKE20		; APPARANTLY NOT, BUMP CR COUNT
	ILDB CHR,AC1		; PICK UP NEXT CHARACTER
	JUMPE CHR,.-1
	CAIE CHR,15		; IF THIS IS A CR, IS DEFINITELY A LONG-LINE CRLF
	JRST MAKE21
MAKE22:	ILDB CHR,AC1		; IN WHICH CASE, READ PAST IT
	CAIE CHR,11
	JRST MAKE22
	JRST MAKE23

MAKE20:	CAIE CHR,EOLCHR		; IF THERE ARE NO MORE CHARACTERS ON NEXT LINE, DON'T BUMP LINE COUNT
MAKE21:	AOS NCRS(J)		; END OF LINE, BREAK THE LINE UP
	TLNE DAT,DMLIN
	JRST MAKE24		; DMs don't need the long line CRLF
	MOVEI CHR,11		; END OF LINE, BREAK LINE
	PUSHJ P,MAKINS
	MOVEI CHR,15
	PUSHJ P,MAKINS
	MOVEI CHR,12
	PUSHJ P,MAKINS
	MOVEI CHR,11
	PUSHJ P,MAKINS
MAKE24:	MOVN AC1,LNLNGT(AC2)	; RESET COLUMN COUNT
MAKEC8:	MOVE TAC1,TAC		; SAVE POINTER
MAKEC9:	ILDB CHR,TAC1		; IS NEXT CHARACTER A NULL?
	JUMPN CHR,MAKEC7	; NO, ALL OK
	MOVE TAC,TAC1		; YES, SPACE POINTER OUT PAST NULLS
	JRST MAKEC9

MAKEC7:	ADDI AC3,1		; BUMP COLUMN COUNT
MAKE10:	CAMN AC3,CCPOS(J)	; IS THIS WHERE THE POINTER IS SUPPOSED TO BE?
	MOVEM TAC,LEPNT1(J)	; YES, STORE IT
	JRST MAKEC1
;MAKEC2 MAKEC6 MAKE17 MAKE18

; HERE WE SEE IF THE TAB IS A REAL TAB OR IF IT IS JUST
; THE THING WE USE TO DELIMIT A LONG-LINE CRLF

MAKEC2:	MOVE TAC1,TAC		; SAVE BYTE POINTER
	ILDB CHR,TAC		; PICK UP NEXT CHARACTER
	CAIE CHR,15		; IS IT A CR?
	JRST MAKEC3		; NO, MUST BE REGULAR TAB, GO ADJUST IT
	SETZ DSER,
	DPB DSER,TAC1		; YES, ZERO OUT THE LONG LINE CRLF
	DPB DSER,TAC
	IDPB DSER,TAC
	IDPB DSER,TAC
	JRST MAKE10

MAKEC6:	SETZ CHR,		; ZERO OUT STUFF AFTER END OF LINE CHARACTER
MAKE17:	LDB TAC1,[POINT 6,TAC,5]
	CAIG TAC1,7		; IS THERE ANY MORE ROOM IN THE LAST TEXT WORD
	JRST MAKE18		; NO, SET UP LELWD AND LEAVE
	IDPB CHR,TAC		; YES, PLOP DOWN A ZERO THERE
	JRST MAKE17

MAKE18:	HRRZ TAC1,TAC		; GET BARE ADDRESS OF LAST TEXT WORD IN BUFFER
	EXCH TAC1,LELWD(J)	; STORE IT AND GET THE OLD VALUE
	MOVE AC1,1(TAC1)	; PICK UP THE RETURN JUMP
	MOVEM AC1,1(TAC)	; PUT IT RIGHT AFTER THE END OF LINE CHARACTER
	POPJ P,
;MAKEC3 MAKEC4 MAKE16

; WE GET HERE WHEN THE TAB SURROUNDS A BUNCH OF SPACES. FIRST WE
; DELETE THE ORIGINAL SPACES, THEN WE FIGURE OUT HOW MANY WE NEED
; TO MAKE THE TAB COME OUT RIGHT AND PUT THEM IN.

MAKEC3:	PUSH P,AC3		; SAVE BYTE POINTER
	PUSH P,UUO		; GET AN ACCUMULATOR FOR COUNTING SPACES IN TABS
	SETZB DSER,UUO
MAKEC4:	DPB DSER,TAC		; ZERO OUT THE SPACES IN THE TAB
	CAIN CHR," "		; COUNT IT AS A SPACE ONLY IF IT REALY IS A SPACE
	ADDI UUO,1		; BUMP NUMBER OF SPACES IN THIS TAB
	ILDB CHR,TAC
	CAIE CHR,11		; UNTIL WE GET TO THE TERMINATING TAB
	JRST MAKEC4
	MOVE TAC,NCRS(J)	; FIGURE OUT POSITION FROM BEGINNING OF FIRST LINE
	ADDI TAC,1		; BUMP BY ONE TO CORRECT FOR NEGATIVITY OF AC1
	IMUL TAC,LNLNGT(AC2)	; MULTIPLY NUMBER OF LINES BY LENGTH OF LINES
	ADD TAC,AC1		; ADD IN CHARACTERS INTO LAST LINE
	MOVEM TAC,LECHPS(J)	; SAVE FOR FUTURE REFERENCE
	MOVN AC3,PPHPOS(J)	; DD/DM bug fix for improper cursor positioning
	ADDM AC3,LECHPS(J)	; PPHPOS was counted in NCRS but not in LEHPOS
	ANDI TAC,7		; MOD 10
	MOVEI AC3,10
	SUB AC3,TAC		; THIS IS NUMBER OF COLUMNS TO GO
	ADD AC1,AC3		; ADD LENGTH OF TAB INTO COLUMN POSITION
	SUBM AC3,UUO		; GET CORRECTION TO THIS TAB
	JUMPLE AC1,MAKE13	; IF NOT AT END OF LINE, GO ON AND ADJUST TAB
	MOVE TAC,TAC1		; GET POINTER TO TAB
	MOVEI CHR," "		; NOW SPACE OUT TO END OF LINE
MAKE16:	CAML AC1,AC3		; OUT FAR ENOUGH?
	JRST MAKE15		; YES, PUT IN CRLF NOW
	PUSHJ P,MAKINS		; NO, PUT IN ANOTHER SPACE
	SOJA AC3,MAKE16
;MAKE15 MAKE13 MAKE14 MAKEC5

; AT THIS POINT, WE ARE IN THE PROCESS OF BREAKING A LONG LINE
; IN THE MIDDLE OF A TAB. WE HAVE JUST INSERTED THE APROPRIATE
; NUMBER OF SPACES TO FILL OUT THE LAST LINE, AND NOW WE
; MUST INSERT THE CRLF ITSELF.

MAKE15:	MOVEI CHR,15
	PUSHJ P,MAKINS		; BREAK LINE IN THE MIDDLE OF A TAB
	MOVEI CHR,12
	PUSHJ P,MAKINS
	AOS NCRS(J)		; UPDATE NUMBER OF CRLFS IN LINE
	MOVE TAC1,TAC		; SAVE BYTE POINTER TO TAB
	MOVE AC3,AC1		; NUMBER OF SPACES IS NUMBER OF CHARACTERS INTO LINE
	SUB AC1,LNLNGT(AC2)	; RESET COLUMN COUNT
MAKE13:	MOVE TAC,LECHPS(J)	; PICK UP NUMBER OF CHARACTERS FROM FIRST LINE
	CAMGE TAC,LEHPOS(J)	; ARE WE BEFORE THE HORIZONTAL POSITION POINTER?
	ADDM UUO,LEHPOS(J)	; YES, UPDATE IT
MAKE14:	POP P,UUO
	MOVE TAC,TAC1		; GET BYTE POINTER BACK
	MOVEI CHR,40
	PUSHJ P,MAKINS		; INSERT THAT MANY SPACES
	SOJG AC3,.-1
	LDB CHR,TAC		; NOW UPDATE POINTER TO PAST TAB
MAKEC5:	CAIN CHR,11
	JRST MAKE11		; THEN GET BACK INTO THE LOOP
	ILDB CHR,TAC		; NOT TAB, GET NEXT CHARACTER
	JRST MAKEC5
;MAKE11 MAKINS

MAKE11:	POP P,AC3		; RESTORE COLUMN COUNT
	JUMPGE AC1,MAKE12	; IF WE GOT LINE OVERFLOW, BREAK LINE UP
	JRST MAKEC8

MAKINS:	ILDB TAC1,TAC		; IS THIS CHARACTER A NULL?
	JUMPE TAC1,.+2
	PUSHJ P,LEINSW		; NO, INSERT A WORD OF NULLS
	DPB CHR,TAC		; DEPOSIT OUR CHARACTER OVER A NULL
	POPJ P,
;QU2DMC QUODMX QUODMC QU2DM3 QU2DM2 PUTDMC PUTDM2 GETLEQ

;Here to put out quoted line editor char which must be followed in same queue
;entry by 1 or 2 other chars.
↑QU2DMC:SKIPN LETXC(J)		;Don't do incremental output if need redraw all
	TLNE IOS,PTLIP		;Don't do anything if PTLoad In Progress
	POPJ P,
	MOVEI AC2,4		;Make sure at least room for 4 chars
	HLRZ AC1,DMLEPT(J)	;Get pointer to end of LE queue
	CAIE AC1,DMLEPT-QLINK(J);Is queue empty?
	CAMLE AC2,QFREE(AC1)	;No, less than 4 bytes of room left?
	JRST QU2DM2		;Yes to one of these, get a new queue entry
	JRST QU2DM3		;No, just do it

;Here to put out a quoted line editor character.
;Make sure room in queue entry for two chars.
QUODMX:	SKIPN LETXC(J)		;Don't do incremental output if need redraw all
	TLNE IOS,PTLIP		;Don't do anything if PTLoad In Progress
	POPJ P,
↑↑QUODMC:			;DMLED enters here (w/scanner off)
	HLRZ AC1,DMLEPT(J)	;Get pointer to end of LE queue
	CAIE AC1,DMLEPT-QLINK(J);Is queue empty?
QU2DM3:	SOSG QFREE(AC1)		;No, less than two bytes of room left?
QU2DM2:	PUSHJ P,GETLEQ		;Yes to one of these, get a new queue entry
	SOS QFREE(AC1)		;Count another byte used up for the 177
	MOVEI AC2,177
	IDPB AC2,QPUTR(AC1)	;Quote the next char
	AOS QDMCNT(AC1)		;Count the 177
	JRST PUTDM2
	
;Routine to place a LE output char in DM's LE queue.
;Scanner channel must be off (if not in it now), or PTLIP bit must be set.
PUTDMC:	SKIPN LETXC(J)		;Don't do incremental output if need redraw all
	TLNE IOS,PTLIP		;Don't do anything if PTLoad In Progress
	POPJ P,
	HLRZ AC1,DMLEPT(J)	;Get pointer to end of LE queue
	CAIE AC1,DMLEPT-QLINK(J);Is queue empty?
	SOSGE QFREE(AC1)	;No, is last queue entry full?
	PUSHJ P,GETLEQ		;Yes to one of these, get a new queue entry
PUTDM2:	IDPB CHR,QPUTR(AC1)	;Insert new char
IFN FTDDFSBUG,< SCPICK > ;CHECK PI STATUS
	AOS QDMCNT(AC1)		;Count another to take out
	POPJ P,

;Routine to set up an empty queue entry in DM's LE queue.
;Called from PUTDMC (above) and DMLED (in DPYSER).
↑↑GETLEQ:
	SETOM LECLK(J)		;Flag clock request soon to be planted for DPLED
	PUSHJ P,GETQ
	MOVEI AC2,QTEXTL*5-1	;Amount of room in queue entry for text, less 1 char
	MOVEM AC2,QFREE(AC1)
	MOVEI AC2,QTEXT(AC1)
	HRLI AC2,440700
	MOVEM AC2,QTAKR(AC1)	;Byte pointer for unpacking LE text
	MOVEM AC2,QPUTR(AC1)	;Byte pointer for storing LE text
	SETZM QDMCNT(AC1)	;No chars in queue entry yet
	HRLM J,QFLAGS(AC1)	;Put pointer to dpy hdr into queue entry
	MOVEI AC2,DMLEXY(J)
	MOVEM AC2,QXYLOC(AC1)	;Store address of X-Y position word
	MOVSI AC2,DPLED		;Plant clk req for DPLED when xfer finishes
	HRR AC2,J		;Pass dpy header address
	MOVEM AC2,QWAKE(AC1)
	MOVEI AC2,LEENQ(J)
	MOVEM AC2,QCOUNT(AC1)
	AOS LEENQ(J)
	MOVEI AC2,DMLEPT-QLINK(J) ;Queue header address
	JRST QDM		;Now queue it

BEND LINED
BEND   TTYSER